mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-01-04 06:01:23 -05:00
Import back-mdb
This commit is contained in:
parent
02cff39398
commit
0ba4206ed9
28 changed files with 12480 additions and 0 deletions
145
doc/man/man5/slapd-mdb.5
Normal file
145
doc/man/man5/slapd-mdb.5
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
.TH SLAPD-MDB 5 "RELEASEDATE" "OpenLDAP LDVERSION"
|
||||
.\" Copyright 2011 The OpenLDAP Foundation All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.\" $OpenLDAP$
|
||||
.SH NAME
|
||||
slapd\-mdb \- Memory-Mapped DB backend to slapd
|
||||
.SH SYNOPSIS
|
||||
.B ETCDIR/slapd.conf
|
||||
.SH DESCRIPTION
|
||||
The \fBmdb\fP backend to
|
||||
.BR slapd (8)
|
||||
uses OpenLDAP's own Memory-Mapped DB (MDB) library to store data.
|
||||
It relies completely on the underlying operating system for memory
|
||||
management and does no caching of its own.
|
||||
.LP
|
||||
The \fBmdb\fP backend is similar to the \fBhdb\fP backend in that
|
||||
it uses a hierarchical database layout which
|
||||
supports subtree renames. It is both more space-efficient and more
|
||||
execution-efficient than the \fBbdb\fP backend, while being overall
|
||||
much simpler to manage.
|
||||
.SH CONFIGURATION
|
||||
These
|
||||
.B slapd.conf
|
||||
options apply to the \fBmdb\fP backend database.
|
||||
That is, they must follow a "database mdb" line and
|
||||
come before any subsequent "backend" or "database" lines.
|
||||
Other database options are described in the
|
||||
.BR slapd.conf (5)
|
||||
manual page.
|
||||
.TP
|
||||
.BI checkpoint \ <kbyte>\ <min>
|
||||
Specify the frequency for flushing the database disk buffers.
|
||||
This setting is only needed if the \fBdbnosync\fP option is used.
|
||||
The checkpoint will occur if either \fI<kbyte>\fP data has been written or
|
||||
\fI<min>\fP minutes have passed since the last checkpoint.
|
||||
Both arguments default to zero, in which case they are ignored. When
|
||||
the \fI<min>\fP argument is non-zero, an internal task will run every
|
||||
\fI<min>\fP minutes to perform the checkpoint.
|
||||
Note: currently the \fI<kbyte>\fP setting is unimplemented.
|
||||
.TP
|
||||
.B dbnosync
|
||||
Specify that on-disk database contents should not be immediately
|
||||
synchronized with in memory changes.
|
||||
Enabling this option may improve performance at the expense of data
|
||||
security. By default, a full data flush/sync is performed when each
|
||||
transaction is committed.
|
||||
.TP
|
||||
.BI directory \ <directory>
|
||||
Specify the directory where the MDB files containing this database and
|
||||
associated indexes live.
|
||||
A separate directory must be specified for each database.
|
||||
The default is
|
||||
.BR LOCALSTATEDIR/openldap\-data .
|
||||
.TP
|
||||
\fBindex \fR{\fI<attrlist>\fR|\fBdefault\fR} [\fBpres\fR,\fBeq\fR,\fBapprox\fR,\fBsub\fR,\fI<special>\fR]
|
||||
Specify the indexes to maintain for the given attribute (or
|
||||
list of attributes).
|
||||
Some attributes only support a subset of indexes.
|
||||
If only an \fI<attr>\fP is given, the indices specified for \fBdefault\fR
|
||||
are maintained.
|
||||
Note that setting a default does not imply that all attributes will be
|
||||
indexed. Also, for best performance, an
|
||||
.B eq
|
||||
index should always be configured for the
|
||||
.B objectClass
|
||||
attribute.
|
||||
|
||||
A number of special index parameters may be specified.
|
||||
The index type
|
||||
.B sub
|
||||
can be decomposed into
|
||||
.BR subinitial ,
|
||||
.BR subany ,\ and
|
||||
.B subfinal
|
||||
indices.
|
||||
The special type
|
||||
.B nolang
|
||||
may be specified to disallow use of this index by language subtypes.
|
||||
The special type
|
||||
.B nosubtypes
|
||||
may be specified to disallow use of this index by named subtypes.
|
||||
Note: changing \fBindex\fP settings in
|
||||
.BR slapd.conf (5)
|
||||
requires rebuilding indices, see
|
||||
.BR slapindex (8);
|
||||
changing \fBindex\fP settings
|
||||
dynamically by LDAPModifying "cn=config" automatically causes rebuilding
|
||||
of the indices online in a background task.
|
||||
.TP
|
||||
.BI maxreaders \ <integer>
|
||||
Specify the maximum number of threads that may have concurrent read access
|
||||
to the database. Tools such as slapcat count as a single thread,
|
||||
in addition to threads in any active slapd processes. The
|
||||
default is 126.
|
||||
.TP
|
||||
.BI maxsize \ <bytes>
|
||||
Specify the maximum size of the database in bytes. A memory map of this
|
||||
size is allocated at startup time and the database will not be allowed
|
||||
to grow beyond this size. The default is 10485760 bytes. This setting
|
||||
may be changed upward if the configured limit needs to be increased.
|
||||
|
||||
Note: It is important to set this to as large a value as possible,
|
||||
(relative to anticipated growth of the actual data over time) since
|
||||
growing the size later may not be practical when the system is under
|
||||
heavy load.
|
||||
.TP
|
||||
.BI mode \ <integer>
|
||||
Specify the file protection mode that newly created database
|
||||
files should have.
|
||||
The default is 0600.
|
||||
.TP
|
||||
.BI searchstack \ <depth>
|
||||
Specify the depth of the stack used for search filter evaluation.
|
||||
Search filters are evaluated on a stack to accommodate nested AND / OR
|
||||
clauses. An individual stack is assigned to each server thread.
|
||||
The depth of the stack determines how complex a filter can be
|
||||
evaluated without requiring any additional memory allocation. Filters that
|
||||
are nested deeper than the search stack depth will cause a separate
|
||||
stack to be allocated for that particular search operation. These
|
||||
allocations can have a major negative impact on server performance,
|
||||
but specifying too much stack will also consume a great deal of memory.
|
||||
Each search stack uses 512K bytes per level. The default stack depth
|
||||
is 16, thus 8MB per thread is used.
|
||||
.SH ACCESS CONTROL
|
||||
The
|
||||
.B mdb
|
||||
backend honors access control semantics as indicated in
|
||||
.BR slapd.access (5).
|
||||
.SH FILES
|
||||
.TP
|
||||
.B ETCDIR/slapd.conf
|
||||
default
|
||||
.B slapd
|
||||
configuration file
|
||||
.SH SEE ALSO
|
||||
.BR slapd.conf (5),
|
||||
.BR slapd\-config (5),
|
||||
.BR slapd (8),
|
||||
.BR slapadd (8),
|
||||
.BR slapcat (8),
|
||||
.BR slapindex (8),
|
||||
OpenLDAP MDB documentation.
|
||||
.SH ACKNOWLEDGEMENTS
|
||||
.so ../Project
|
||||
Written by Howard Chu.
|
||||
61
servers/slapd/back-mdb/Makefile.in
Normal file
61
servers/slapd/back-mdb/Makefile.in
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# Makefile.in for back-mdb
|
||||
# $OpenLDAP$
|
||||
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
##
|
||||
## Copyright 2011 The OpenLDAP Foundation.
|
||||
## 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>.
|
||||
|
||||
SRCS = init.c tools.c config.c \
|
||||
add.c bind.c compare.c delete.c modify.c modrdn.c search.c \
|
||||
extended.c referral.c operational.c \
|
||||
attr.c index.c key.c filterindex.c \
|
||||
dn2entry.c dn2id.c id2entry.c idl.c \
|
||||
nextid.c monitor.c
|
||||
|
||||
OBJS = init.lo tools.lo config.lo \
|
||||
add.lo bind.lo compare.lo delete.lo modify.lo modrdn.lo search.lo \
|
||||
extended.lo referral.lo operational.lo \
|
||||
attr.lo index.lo key.lo filterindex.lo \
|
||||
dn2entry.lo dn2id.lo id2entry.lo idl.lo \
|
||||
nextid.lo monitor.lo mdb.lo midl.lo
|
||||
|
||||
LDAP_INCDIR= ../../../include
|
||||
LDAP_LIBDIR= ../../../libraries
|
||||
|
||||
BUILD_OPT = "--enable-mdb"
|
||||
BUILD_MOD = @BUILD_MDB@
|
||||
|
||||
mod_DEFS = -DSLAPD_IMPORT
|
||||
MOD_DEFS = $(@BUILD_MDB@_DEFS)
|
||||
MOD_LIBS = $(MDB_LIBS)
|
||||
|
||||
shared_LDAP_LIBS = $(LDAP_LIBLDAP_R_LA) $(LDAP_LIBLBER_LA)
|
||||
NT_LINK_LIBS = -L.. -lslapd $(@BUILD_LIBS_DYNAMIC@_LDAP_LIBS)
|
||||
UNIX_LINK_LIBS = $(@BUILD_LIBS_DYNAMIC@_LDAP_LIBS)
|
||||
|
||||
LIBBASE = back_mdb
|
||||
|
||||
XINCPATH = -I.. -I$(srcdir)/.. -I$(srcdir)/$(LDAP_LIBDIR)/libmdb
|
||||
XDEFS = $(MODULES_CPPFLAGS)
|
||||
|
||||
all-local-lib: ../.backend
|
||||
|
||||
../.backend: lib$(LIBBASE).a
|
||||
@touch $@
|
||||
|
||||
mdb.lo: $(srcdir)/$(LDAP_LIBDIR)/libmdb/mdb.c
|
||||
$(LTCOMPILE_MOD) $<
|
||||
|
||||
midl.lo: $(srcdir)/$(LDAP_LIBDIR)/libmdb/midl.c
|
||||
$(LTCOMPILE_MOD) $<
|
||||
|
||||
veryclean-local-lib: FORCE
|
||||
$(RM) $(XXHEADERS) $(XXSRCS) .links
|
||||
438
servers/slapd/back-mdb/add.c
Normal file
438
servers/slapd/back-mdb/add.c
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
/* add.c - ldap mdb back-end add routine */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ac/string.h>
|
||||
|
||||
#include "back-mdb.h"
|
||||
|
||||
int
|
||||
mdb_add(Operation *op, SlapReply *rs )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
|
||||
struct berval pdn;
|
||||
Entry *p = NULL, *oe = op->ora_e;
|
||||
char textbuf[SLAP_TEXT_BUFLEN];
|
||||
size_t textlen = sizeof textbuf;
|
||||
AttributeDescription *children = slap_schema.si_ad_children;
|
||||
AttributeDescription *entry = slap_schema.si_ad_entry;
|
||||
MDB_txn *txn = NULL;
|
||||
ID eid = NOID, pid = 0;
|
||||
mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;
|
||||
int subentry;
|
||||
|
||||
int success;
|
||||
|
||||
LDAPControl **postread_ctrl = NULL;
|
||||
LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
|
||||
int num_ctrls = 0;
|
||||
|
||||
#ifdef LDAP_X_TXN
|
||||
int settle = 0;
|
||||
#endif
|
||||
|
||||
Debug(LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(mdb_add) ": %s\n",
|
||||
op->ora_e->e_name.bv_val, 0, 0);
|
||||
|
||||
#ifdef LDAP_X_TXN
|
||||
if( op->o_txnSpec ) {
|
||||
/* acquire connection lock */
|
||||
ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
|
||||
if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
|
||||
rs->sr_text = "invalid transaction identifier";
|
||||
rs->sr_err = LDAP_X_TXN_ID_INVALID;
|
||||
goto txnReturn;
|
||||
} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
|
||||
settle=1;
|
||||
goto txnReturn;
|
||||
}
|
||||
|
||||
if( op->o_conn->c_txn_backend == NULL ) {
|
||||
op->o_conn->c_txn_backend = op->o_bd;
|
||||
|
||||
} else if( op->o_conn->c_txn_backend != op->o_bd ) {
|
||||
rs->sr_text = "transaction cannot span multiple database contexts";
|
||||
rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
|
||||
goto txnReturn;
|
||||
}
|
||||
|
||||
/* insert operation into transaction */
|
||||
|
||||
rs->sr_text = "transaction specified";
|
||||
rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
|
||||
|
||||
txnReturn:
|
||||
/* release connection lock */
|
||||
ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
|
||||
|
||||
if( !settle ) {
|
||||
send_ldap_result( op, rs );
|
||||
return rs->sr_err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ctrls[num_ctrls] = 0;
|
||||
|
||||
/* check entry's schema */
|
||||
rs->sr_err = entry_schema_check( op, op->ora_e, NULL,
|
||||
get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen );
|
||||
if ( rs->sr_err != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": entry failed schema check: "
|
||||
"%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* add opattrs to shadow as well, only missing attrs will actually
|
||||
* be added; helps compatibility with older OL versions */
|
||||
rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );
|
||||
if ( rs->sr_err != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": entry failed op attrs add: "
|
||||
"%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
if ( get_assert( op ) &&
|
||||
( test_filter( op, op->ora_e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
|
||||
{
|
||||
rs->sr_err = LDAP_ASSERTION_FAILED;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
subentry = is_entry_subentry( op->ora_e );
|
||||
|
||||
/* begin transaction */
|
||||
rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi );
|
||||
rs->sr_text = NULL;
|
||||
if( rs->sr_err != 0 ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": txn_begin failed: %s (%d)\n",
|
||||
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
txn = moi->moi_txn;
|
||||
|
||||
/*
|
||||
* Get the parent dn and see if the corresponding entry exists.
|
||||
*/
|
||||
if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) {
|
||||
pdn = slap_empty_bv;
|
||||
} else {
|
||||
dnParent( &op->ora_e->e_nname, &pdn );
|
||||
}
|
||||
|
||||
/* get entry or parent */
|
||||
rs->sr_err = mdb_dn2entry( op, txn, &op->ora_e->e_nname, &p, 1 );
|
||||
switch( rs->sr_err ) {
|
||||
case 0:
|
||||
rs->sr_err = LDAP_ALREADY_EXISTS;
|
||||
mdb_entry_return( p );
|
||||
p = NULL;
|
||||
goto return_results;
|
||||
case MDB_NOTFOUND:
|
||||
break;
|
||||
case LDAP_BUSY:
|
||||
rs->sr_text = "ldap server busy";
|
||||
goto return_results;
|
||||
default:
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
if ( !p )
|
||||
p = (Entry *)&slap_entry_root;
|
||||
|
||||
if ( !bvmatch( &pdn, &p->e_nname ) ) {
|
||||
rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
|
||||
op->o_tmpmemctx );
|
||||
if ( p != (Entry *)&slap_entry_root && is_entry_referral( p )) {
|
||||
BerVarray ref = get_entry_referrals( op, p );
|
||||
rs->sr_ref = referral_rewrite( ref, &p->e_name,
|
||||
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
|
||||
ber_bvarray_free( ref );
|
||||
} else {
|
||||
rs->sr_ref = NULL;
|
||||
}
|
||||
if ( p != (Entry *)&slap_entry_root )
|
||||
mdb_entry_return( p );
|
||||
p = NULL;
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": parent "
|
||||
"does not exist\n", 0, 0, 0 );
|
||||
|
||||
rs->sr_err = LDAP_REFERRAL;
|
||||
rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
rs->sr_err = access_allowed( op, p,
|
||||
children, NULL, ACL_WADD, NULL );
|
||||
|
||||
if ( ! rs->sr_err ) {
|
||||
if ( p != (Entry *)&slap_entry_root )
|
||||
mdb_entry_return( p );
|
||||
p = NULL;
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": no write access to parent\n",
|
||||
0, 0, 0 );
|
||||
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
||||
rs->sr_text = "no write access to parent";
|
||||
goto return_results;;
|
||||
}
|
||||
|
||||
if ( p != (Entry *)&slap_entry_root ) {
|
||||
if ( is_entry_subentry( p ) ) {
|
||||
mdb_entry_return( p );
|
||||
p = NULL;
|
||||
/* parent is a subentry, don't allow add */
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": parent is subentry\n",
|
||||
0, 0, 0 );
|
||||
rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
|
||||
rs->sr_text = "parent is a subentry";
|
||||
goto return_results;;
|
||||
}
|
||||
|
||||
if ( is_entry_alias( p ) ) {
|
||||
mdb_entry_return( p );
|
||||
p = NULL;
|
||||
/* parent is an alias, don't allow add */
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": parent is alias\n",
|
||||
0, 0, 0 );
|
||||
rs->sr_err = LDAP_ALIAS_PROBLEM;
|
||||
rs->sr_text = "parent is an alias";
|
||||
goto return_results;;
|
||||
}
|
||||
|
||||
if ( is_entry_referral( p ) ) {
|
||||
BerVarray ref = get_entry_referrals( op, p );
|
||||
/* parent is a referral, don't allow add */
|
||||
rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
|
||||
op->o_tmpmemctx );
|
||||
rs->sr_ref = referral_rewrite( ref, &p->e_name,
|
||||
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
|
||||
ber_bvarray_free( ref );
|
||||
mdb_entry_return( p );
|
||||
p = NULL;
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": parent is referral\n",
|
||||
0, 0, 0 );
|
||||
|
||||
rs->sr_err = LDAP_REFERRAL;
|
||||
rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( subentry ) {
|
||||
/* FIXME: */
|
||||
/* parent must be an administrative point of the required kind */
|
||||
}
|
||||
|
||||
/* free parent */
|
||||
if ( p != (Entry *)&slap_entry_root ) {
|
||||
pid = p->e_id;
|
||||
if ( p->e_nname.bv_len ) {
|
||||
struct berval ppdn;
|
||||
|
||||
/* ITS#5326: use parent's DN if differs from provided one */
|
||||
dnParent( &op->ora_e->e_name, &ppdn );
|
||||
if ( !dn_match( &p->e_name, &ppdn ) ) {
|
||||
struct berval rdn;
|
||||
struct berval newdn;
|
||||
|
||||
dnRdn( &op->ora_e->e_name, &rdn );
|
||||
|
||||
build_new_dn( &newdn, &p->e_name, &rdn, NULL );
|
||||
if ( op->ora_e->e_name.bv_val != op->o_req_dn.bv_val )
|
||||
ber_memfree( op->ora_e->e_name.bv_val );
|
||||
op->ora_e->e_name = newdn;
|
||||
|
||||
/* FIXME: should check whether
|
||||
* dnNormalize(newdn) == e->e_nname ... */
|
||||
}
|
||||
}
|
||||
|
||||
mdb_entry_return( p );
|
||||
}
|
||||
p = NULL;
|
||||
|
||||
rs->sr_err = access_allowed( op, op->ora_e,
|
||||
entry, NULL, ACL_WADD, NULL );
|
||||
|
||||
if ( ! rs->sr_err ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": no write access to entry\n",
|
||||
0, 0, 0 );
|
||||
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
||||
rs->sr_text = "no write access to entry";
|
||||
goto return_results;;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check ACL for attribute write access
|
||||
*/
|
||||
if (!acl_check_modlist(op, oe, op->ora_modlist)) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": no write access to attribute\n",
|
||||
0, 0, 0 );
|
||||
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
||||
rs->sr_text = "no write access to attribute";
|
||||
goto return_results;;
|
||||
}
|
||||
|
||||
if ( eid == NOID ) {
|
||||
rs->sr_err = mdb_next_id( op->o_bd, txn, &eid );
|
||||
if( rs->sr_err != 0 ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": next_id failed (%d)\n",
|
||||
rs->sr_err, 0, 0 );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
op->ora_e->e_id = eid;
|
||||
}
|
||||
|
||||
/* dn2id index */
|
||||
rs->sr_err = mdb_dn2id_add( op, txn, pid, op->ora_e );
|
||||
if ( rs->sr_err != 0 ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": dn2id_add failed: %s (%d)\n",
|
||||
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
|
||||
switch( rs->sr_err ) {
|
||||
case MDB_KEYEXIST:
|
||||
rs->sr_err = LDAP_ALREADY_EXISTS;
|
||||
break;
|
||||
default:
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
}
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* attribute indexes */
|
||||
rs->sr_err = mdb_index_entry_add( op, txn, op->ora_e );
|
||||
if ( rs->sr_err != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": index_entry_add failed\n",
|
||||
0, 0, 0 );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "index generation failed";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* id2entry index */
|
||||
rs->sr_err = mdb_id2entry_add( op, txn, op->ora_e );
|
||||
if ( rs->sr_err != 0 ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": id2entry_add failed\n",
|
||||
0, 0, 0 );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "entry store failed";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* post-read */
|
||||
if( op->o_postread ) {
|
||||
if( postread_ctrl == NULL ) {
|
||||
postread_ctrl = &ctrls[num_ctrls++];
|
||||
ctrls[num_ctrls] = NULL;
|
||||
}
|
||||
if ( slap_read_controls( op, rs, op->ora_e,
|
||||
&slap_post_read_bv, postread_ctrl ) )
|
||||
{
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_add) ": post-read "
|
||||
"failed!\n", 0, 0, 0 );
|
||||
if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
|
||||
/* FIXME: is it correct to abort
|
||||
* operation if control fails? */
|
||||
goto return_results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( moi == &opinfo ) {
|
||||
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
|
||||
opinfo.moi_oe.oe_key = NULL;
|
||||
if ( op->o_noop ) {
|
||||
mdb_txn_abort( txn );
|
||||
rs->sr_err = LDAP_X_NO_OPERATION;
|
||||
txn = NULL;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
if (( rs->sr_err = mdb_txn_commit( txn )) != 0 ) {
|
||||
rs->sr_text = "txn_commit failed";
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": %s : %s (%d)\n",
|
||||
rs->sr_text, mdb_strerror(rs->sr_err), rs->sr_err );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
goto return_results;
|
||||
}
|
||||
txn = NULL;
|
||||
}
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_add) ": added%s id=%08lx dn=\"%s\"\n",
|
||||
op->o_noop ? " (no-op)" : "",
|
||||
op->ora_e->e_id, op->ora_e->e_dn );
|
||||
|
||||
rs->sr_text = NULL;
|
||||
if( num_ctrls ) rs->sr_ctrls = ctrls;
|
||||
|
||||
return_results:
|
||||
success = rs->sr_err;
|
||||
send_ldap_result( op, rs );
|
||||
|
||||
if( moi == &opinfo ) {
|
||||
if( txn != NULL ) {
|
||||
mdb_txn_abort( txn );
|
||||
}
|
||||
if ( opinfo.moi_oe.oe_key ) {
|
||||
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
|
||||
}
|
||||
}
|
||||
|
||||
if( success == LDAP_SUCCESS ) {
|
||||
#if 0
|
||||
if ( mdb->bi_txn_cp_kbyte ) {
|
||||
TXN_CHECKPOINT( mdb->bi_dbenv,
|
||||
mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
slap_graduate_commit_csn( op );
|
||||
|
||||
if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
|
||||
slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
|
||||
slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
|
||||
}
|
||||
return rs->sr_err;
|
||||
}
|
||||
522
servers/slapd/back-mdb/attr.c
Normal file
522
servers/slapd/back-mdb/attr.c
Normal file
|
|
@ -0,0 +1,522 @@
|
|||
/* attr.c - backend routines for dealing with attributes */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/socket.h>
|
||||
#include <ac/string.h>
|
||||
|
||||
#include "slap.h"
|
||||
#include "back-mdb.h"
|
||||
#include "config.h"
|
||||
#include "lutil.h"
|
||||
|
||||
/* Find the ad, return -1 if not found,
|
||||
* set point for insertion if ins is non-NULL
|
||||
*/
|
||||
int
|
||||
mdb_attr_slot( struct mdb_info *mdb, AttributeDescription *ad, int *ins )
|
||||
{
|
||||
unsigned base = 0, cursor = 0;
|
||||
unsigned n = mdb->mi_nattrs;
|
||||
int val = 0;
|
||||
|
||||
while ( 0 < n ) {
|
||||
unsigned pivot = n >> 1;
|
||||
cursor = base + pivot;
|
||||
|
||||
val = SLAP_PTRCMP( ad, mdb->mi_attrs[cursor]->ai_desc );
|
||||
if ( val < 0 ) {
|
||||
n = pivot;
|
||||
} else if ( val > 0 ) {
|
||||
base = cursor + 1;
|
||||
n -= pivot + 1;
|
||||
} else {
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
if ( ins ) {
|
||||
if ( val > 0 )
|
||||
++cursor;
|
||||
*ins = cursor;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
ainfo_insert( struct mdb_info *mdb, AttrInfo *a )
|
||||
{
|
||||
int x;
|
||||
int i = mdb_attr_slot( mdb, a->ai_desc, &x );
|
||||
|
||||
/* Is it a dup? */
|
||||
if ( i >= 0 )
|
||||
return -1;
|
||||
|
||||
mdb->mi_attrs = ch_realloc( mdb->mi_attrs, ( mdb->mi_nattrs+1 ) *
|
||||
sizeof( AttrInfo * ));
|
||||
if ( x < mdb->mi_nattrs )
|
||||
AC_MEMCPY( &mdb->mi_attrs[x+1], &mdb->mi_attrs[x],
|
||||
( mdb->mi_nattrs - x ) * sizeof( AttrInfo *));
|
||||
mdb->mi_attrs[x] = a;
|
||||
mdb->mi_nattrs++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
AttrInfo *
|
||||
mdb_attr_mask(
|
||||
struct mdb_info *mdb,
|
||||
AttributeDescription *desc )
|
||||
{
|
||||
int i = mdb_attr_slot( mdb, desc, NULL );
|
||||
return i < 0 ? NULL : mdb->mi_attrs[i];
|
||||
}
|
||||
|
||||
/* Open all un-opened index DB handles */
|
||||
int
|
||||
mdb_attr_dbs_open(
|
||||
BackendDB *be, MDB_txn *tx0, ConfigReply *cr )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
|
||||
MDB_txn *txn;
|
||||
int i, flags;
|
||||
int rc;
|
||||
|
||||
txn = tx0;
|
||||
if ( txn == NULL ) {
|
||||
rc = mdb_txn_begin( mdb->mi_dbenv, 0, &txn );
|
||||
if ( rc ) {
|
||||
snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
|
||||
"txn_begin failed: %s (%d).",
|
||||
be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
|
||||
cr->msg, 0, 0 );
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
flags = MDB_DUPSORT|MDB_DUPFIXED|MDB_INTEGERDUP;
|
||||
if ( !(slapMode & SLAP_TOOL_READONLY) )
|
||||
flags |= MDB_CREATE;
|
||||
|
||||
for ( i=0; i<mdb->mi_nattrs; i++ ) {
|
||||
if ( mdb->mi_attrs[i]->ai_dbi ) /* already open */
|
||||
continue;
|
||||
rc = mdb_open( txn, mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
|
||||
flags, &mdb->mi_attrs[i]->ai_dbi );
|
||||
if ( rc ) {
|
||||
snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
|
||||
"mdb_open(%s) failed: %s (%d).",
|
||||
be->be_suffix[0].bv_val,
|
||||
mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
|
||||
mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
|
||||
cr->msg, 0, 0 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only commit if this is our txn */
|
||||
if ( tx0 == NULL ) {
|
||||
if ( !rc ) {
|
||||
rc = mdb_txn_commit( txn );
|
||||
if ( rc ) {
|
||||
snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
|
||||
"txn_commit failed: %s (%d).",
|
||||
be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
|
||||
cr->msg, 0, 0 );
|
||||
}
|
||||
} else {
|
||||
mdb_txn_abort( txn );
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
mdb_attr_dbs_close(
|
||||
struct mdb_info *mdb,
|
||||
MDB_txn *txn
|
||||
)
|
||||
{
|
||||
int i;
|
||||
for ( i=0; i<mdb->mi_nattrs; i++ )
|
||||
if ( mdb->mi_attrs[i]->ai_dbi )
|
||||
mdb_close( txn, mdb->mi_attrs[i]->ai_dbi );
|
||||
}
|
||||
|
||||
int
|
||||
mdb_attr_index_config(
|
||||
struct mdb_info *mdb,
|
||||
const char *fname,
|
||||
int lineno,
|
||||
int argc,
|
||||
char **argv,
|
||||
struct config_reply_s *c_reply)
|
||||
{
|
||||
int rc = 0;
|
||||
int i;
|
||||
slap_mask_t mask;
|
||||
char **attrs;
|
||||
char **indexes = NULL;
|
||||
|
||||
attrs = ldap_str2charray( argv[0], "," );
|
||||
|
||||
if( attrs == NULL ) {
|
||||
fprintf( stderr, "%s: line %d: "
|
||||
"no attributes specified: %s\n",
|
||||
fname, lineno, argv[0] );
|
||||
return LDAP_PARAM_ERROR;
|
||||
}
|
||||
|
||||
if ( argc > 1 ) {
|
||||
indexes = ldap_str2charray( argv[1], "," );
|
||||
|
||||
if( indexes == NULL ) {
|
||||
fprintf( stderr, "%s: line %d: "
|
||||
"no indexes specified: %s\n",
|
||||
fname, lineno, argv[1] );
|
||||
rc = LDAP_PARAM_ERROR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if( indexes == NULL ) {
|
||||
mask = mdb->mi_defaultmask;
|
||||
|
||||
} else {
|
||||
mask = 0;
|
||||
|
||||
for ( i = 0; indexes[i] != NULL; i++ ) {
|
||||
slap_mask_t index;
|
||||
rc = slap_str2index( indexes[i], &index );
|
||||
|
||||
if( rc != LDAP_SUCCESS ) {
|
||||
if ( c_reply )
|
||||
{
|
||||
snprintf(c_reply->msg, sizeof(c_reply->msg),
|
||||
"index type \"%s\" undefined", indexes[i] );
|
||||
|
||||
fprintf( stderr, "%s: line %d: %s\n",
|
||||
fname, lineno, c_reply->msg );
|
||||
}
|
||||
rc = LDAP_PARAM_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
mask |= index;
|
||||
}
|
||||
}
|
||||
|
||||
if( !mask ) {
|
||||
if ( c_reply )
|
||||
{
|
||||
snprintf(c_reply->msg, sizeof(c_reply->msg),
|
||||
"no indexes selected" );
|
||||
fprintf( stderr, "%s: line %d: %s\n",
|
||||
fname, lineno, c_reply->msg );
|
||||
}
|
||||
rc = LDAP_PARAM_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
for ( i = 0; attrs[i] != NULL; i++ ) {
|
||||
AttrInfo *a;
|
||||
AttributeDescription *ad;
|
||||
const char *text;
|
||||
#ifdef LDAP_COMP_MATCH
|
||||
ComponentReference* cr = NULL;
|
||||
AttrInfo *a_cr = NULL;
|
||||
#endif
|
||||
|
||||
if( strcasecmp( attrs[i], "default" ) == 0 ) {
|
||||
mdb->mi_defaultmask |= mask;
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef LDAP_COMP_MATCH
|
||||
if ( is_component_reference( attrs[i] ) ) {
|
||||
rc = extract_component_reference( attrs[i], &cr );
|
||||
if ( rc != LDAP_SUCCESS ) {
|
||||
if ( c_reply )
|
||||
{
|
||||
snprintf(c_reply->msg, sizeof(c_reply->msg),
|
||||
"index component reference\"%s\" undefined",
|
||||
attrs[i] );
|
||||
fprintf( stderr, "%s: line %d: %s\n",
|
||||
fname, lineno, c_reply->msg );
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
cr->cr_indexmask = mask;
|
||||
/*
|
||||
* After extracting a component reference
|
||||
* only the name of a attribute will be remaining
|
||||
*/
|
||||
} else {
|
||||
cr = NULL;
|
||||
}
|
||||
#endif
|
||||
ad = NULL;
|
||||
rc = slap_str2ad( attrs[i], &ad, &text );
|
||||
|
||||
if( rc != LDAP_SUCCESS ) {
|
||||
if ( c_reply )
|
||||
{
|
||||
snprintf(c_reply->msg, sizeof(c_reply->msg),
|
||||
"index attribute \"%s\" undefined",
|
||||
attrs[i] );
|
||||
|
||||
fprintf( stderr, "%s: line %d: %s\n",
|
||||
fname, lineno, c_reply->msg );
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
if( ad == slap_schema.si_ad_entryDN || slap_ad_is_binary( ad ) ) {
|
||||
if (c_reply) {
|
||||
snprintf(c_reply->msg, sizeof(c_reply->msg),
|
||||
"index of attribute \"%s\" disallowed", attrs[i] );
|
||||
fprintf( stderr, "%s: line %d: %s\n",
|
||||
fname, lineno, c_reply->msg );
|
||||
}
|
||||
rc = LDAP_UNWILLING_TO_PERFORM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
|
||||
ad->ad_type->sat_approx
|
||||
&& ad->ad_type->sat_approx->smr_indexer
|
||||
&& ad->ad_type->sat_approx->smr_filter ) )
|
||||
{
|
||||
if (c_reply) {
|
||||
snprintf(c_reply->msg, sizeof(c_reply->msg),
|
||||
"approx index of attribute \"%s\" disallowed", attrs[i] );
|
||||
fprintf( stderr, "%s: line %d: %s\n",
|
||||
fname, lineno, c_reply->msg );
|
||||
}
|
||||
rc = LDAP_INAPPROPRIATE_MATCHING;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !(
|
||||
ad->ad_type->sat_equality
|
||||
&& ad->ad_type->sat_equality->smr_indexer
|
||||
&& ad->ad_type->sat_equality->smr_filter ) )
|
||||
{
|
||||
if (c_reply) {
|
||||
snprintf(c_reply->msg, sizeof(c_reply->msg),
|
||||
"equality index of attribute \"%s\" disallowed", attrs[i] );
|
||||
fprintf( stderr, "%s: line %d: %s\n",
|
||||
fname, lineno, c_reply->msg );
|
||||
}
|
||||
rc = LDAP_INAPPROPRIATE_MATCHING;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
|
||||
ad->ad_type->sat_substr
|
||||
&& ad->ad_type->sat_substr->smr_indexer
|
||||
&& ad->ad_type->sat_substr->smr_filter ) )
|
||||
{
|
||||
if (c_reply) {
|
||||
snprintf(c_reply->msg, sizeof(c_reply->msg),
|
||||
"substr index of attribute \"%s\" disallowed", attrs[i] );
|
||||
fprintf( stderr, "%s: line %d: %s\n",
|
||||
fname, lineno, c_reply->msg );
|
||||
}
|
||||
rc = LDAP_INAPPROPRIATE_MATCHING;
|
||||
goto done;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
|
||||
ad->ad_cname.bv_val, mask, 0 );
|
||||
|
||||
a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );
|
||||
|
||||
#ifdef LDAP_COMP_MATCH
|
||||
a->ai_cr = NULL;
|
||||
#endif
|
||||
a->ai_desc = ad;
|
||||
a->ai_dbi = 0;
|
||||
|
||||
if ( mdb->mi_flags & MDB_IS_OPEN ) {
|
||||
a->ai_indexmask = 0;
|
||||
a->ai_newmask = mask;
|
||||
} else {
|
||||
a->ai_indexmask = mask;
|
||||
a->ai_newmask = 0;
|
||||
}
|
||||
|
||||
#ifdef LDAP_COMP_MATCH
|
||||
if ( cr ) {
|
||||
a_cr = mdb_attr_mask( mdb, ad );
|
||||
if ( a_cr ) {
|
||||
/*
|
||||
* AttrInfo is already in AVL
|
||||
* just add the extracted component reference
|
||||
* in the AttrInfo
|
||||
*/
|
||||
rc = insert_component_reference( cr, &a_cr->ai_cr );
|
||||
if ( rc != LDAP_SUCCESS) {
|
||||
fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
|
||||
rc = LDAP_PARAM_ERROR;
|
||||
goto done;
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
rc = insert_component_reference( cr, &a->ai_cr );
|
||||
if ( rc != LDAP_SUCCESS) {
|
||||
fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
|
||||
rc = LDAP_PARAM_ERROR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
rc = ainfo_insert( mdb, a );
|
||||
if( rc ) {
|
||||
if ( mdb->mi_flags & MDB_IS_OPEN ) {
|
||||
AttrInfo *b = mdb_attr_mask( mdb, ad );
|
||||
/* If there is already an index defined for this attribute
|
||||
* it must be replaced. Otherwise we end up with multiple
|
||||
* olcIndex values for the same attribute */
|
||||
if ( b->ai_indexmask & MDB_INDEX_DELETING ) {
|
||||
/* If we were editing this attr, reset it */
|
||||
b->ai_indexmask &= ~MDB_INDEX_DELETING;
|
||||
/* If this is leftover from a previous add, commit it */
|
||||
if ( b->ai_newmask )
|
||||
b->ai_indexmask = b->ai_newmask;
|
||||
b->ai_newmask = a->ai_newmask;
|
||||
ch_free( a );
|
||||
rc = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (c_reply) {
|
||||
snprintf(c_reply->msg, sizeof(c_reply->msg),
|
||||
"duplicate index definition for attr \"%s\"",
|
||||
attrs[i] );
|
||||
fprintf( stderr, "%s: line %d: %s\n",
|
||||
fname, lineno, c_reply->msg );
|
||||
}
|
||||
|
||||
rc = LDAP_PARAM_ERROR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
ldap_charray_free( attrs );
|
||||
if ( indexes != NULL ) ldap_charray_free( indexes );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
mdb_attr_index_unparser( void *v1, void *v2 )
|
||||
{
|
||||
AttrInfo *ai = v1;
|
||||
BerVarray *bva = v2;
|
||||
struct berval bv;
|
||||
char *ptr;
|
||||
|
||||
slap_index2bvlen( ai->ai_indexmask, &bv );
|
||||
if ( bv.bv_len ) {
|
||||
bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
|
||||
ptr = ch_malloc( bv.bv_len+1 );
|
||||
bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
|
||||
*bv.bv_val++ = ' ';
|
||||
slap_index2bv( ai->ai_indexmask, &bv );
|
||||
bv.bv_val = ptr;
|
||||
ber_bvarray_add( bva, &bv );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static AttributeDescription addef = { NULL, NULL, BER_BVC("default") };
|
||||
static AttrInfo aidef = { &addef };
|
||||
|
||||
void
|
||||
mdb_attr_index_unparse( struct mdb_info *mdb, BerVarray *bva )
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( mdb->mi_defaultmask ) {
|
||||
aidef.ai_indexmask = mdb->mi_defaultmask;
|
||||
mdb_attr_index_unparser( &aidef, bva );
|
||||
}
|
||||
for ( i=0; i<mdb->mi_nattrs; i++ )
|
||||
mdb_attr_index_unparser( mdb->mi_attrs[i], bva );
|
||||
}
|
||||
|
||||
void
|
||||
mdb_attr_info_free( AttrInfo *ai )
|
||||
{
|
||||
#ifdef LDAP_COMP_MATCH
|
||||
free( ai->ai_cr );
|
||||
#endif
|
||||
free( ai );
|
||||
}
|
||||
|
||||
void
|
||||
mdb_attr_index_destroy( struct mdb_info *mdb )
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i=0; i<mdb->mi_nattrs; i++ )
|
||||
mdb_attr_info_free( mdb->mi_attrs[i] );
|
||||
|
||||
free( mdb->mi_attrs );
|
||||
}
|
||||
|
||||
void mdb_attr_index_free( struct mdb_info *mdb, AttributeDescription *ad )
|
||||
{
|
||||
int i;
|
||||
|
||||
i = mdb_attr_slot( mdb, ad, NULL );
|
||||
if ( i >= 0 ) {
|
||||
mdb_attr_info_free( mdb->mi_attrs[i] );
|
||||
mdb->mi_nattrs--;
|
||||
for (; i<mdb->mi_nattrs; i++)
|
||||
mdb->mi_attrs[i] = mdb->mi_attrs[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
void mdb_attr_flush( struct mdb_info *mdb )
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i=0; i<mdb->mi_nattrs; i++ ) {
|
||||
if ( mdb->mi_attrs[i]->ai_indexmask & MDB_INDEX_DELETING ) {
|
||||
int j;
|
||||
mdb_attr_info_free( mdb->mi_attrs[i] );
|
||||
mdb->mi_nattrs--;
|
||||
for (j=i; j<mdb->mi_nattrs; j++)
|
||||
mdb->mi_attrs[j] = mdb->mi_attrs[j+1];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
162
servers/slapd/back-mdb/back-mdb.h
Normal file
162
servers/slapd/back-mdb/back-mdb.h
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/* back-mdb.h - mdb back-end header file */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#ifndef _BACK_MDB_H_
|
||||
#define _BACK_MDB_H_
|
||||
|
||||
#include <portable.h>
|
||||
#include "slap.h"
|
||||
#include "mdb.h"
|
||||
|
||||
LDAP_BEGIN_DECL
|
||||
|
||||
#define DN_BASE_PREFIX SLAP_INDEX_EQUALITY_PREFIX
|
||||
#define DN_ONE_PREFIX '%'
|
||||
#define DN_SUBTREE_PREFIX '@'
|
||||
|
||||
#define MDB_AD2ID 0
|
||||
#define MDB_DN2ID 1
|
||||
#define MDB_ID2ENTRY 2
|
||||
#define MDB_NDB 3
|
||||
|
||||
/* The default search IDL stack cache depth */
|
||||
#define DEFAULT_SEARCH_STACK_DEPTH 16
|
||||
|
||||
/* The minimum we can function with */
|
||||
#define MINIMUM_SEARCH_STACK_DEPTH 8
|
||||
|
||||
#define MDB_INDICES 128
|
||||
|
||||
/* Default to 10MB max */
|
||||
#define DEFAULT_MAPSIZE (10*1048576)
|
||||
|
||||
#ifdef LDAP_DEVEL
|
||||
#define MDB_MONITOR_IDX
|
||||
#endif /* LDAP_DEVEL */
|
||||
|
||||
typedef struct mdb_monitor_t {
|
||||
void *mdm_cb;
|
||||
struct berval mdm_ndn;
|
||||
} mdb_monitor_t;
|
||||
|
||||
/* From ldap_rq.h */
|
||||
struct re_s;
|
||||
|
||||
struct mdb_info {
|
||||
MDB_env *mi_dbenv;
|
||||
|
||||
/* DB_ENV parameters */
|
||||
/* The DB_ENV can be tuned via DB_CONFIG */
|
||||
char *mi_dbenv_home;
|
||||
u_int32_t mi_dbenv_flags;
|
||||
int mi_dbenv_mode;
|
||||
|
||||
size_t mi_mapsize;
|
||||
|
||||
slap_mask_t mi_defaultmask;
|
||||
int mi_nattrs;
|
||||
struct mdb_attrinfo **mi_attrs;
|
||||
void *mi_search_stack;
|
||||
int mi_search_stack_depth;
|
||||
int mi_readers;
|
||||
|
||||
int mi_txn_cp;
|
||||
u_int32_t mi_txn_cp_min;
|
||||
u_int32_t mi_txn_cp_kbyte;
|
||||
struct re_s *mi_txn_cp_task;
|
||||
struct re_s *mi_index_task;
|
||||
|
||||
mdb_monitor_t mi_monitor;
|
||||
|
||||
#ifdef MDB_MONITOR_IDX
|
||||
ldap_pvt_thread_mutex_t mi_idx_mutex;
|
||||
Avlnode *mi_idx;
|
||||
#endif /* MDB_MONITOR_IDX */
|
||||
|
||||
int mi_flags;
|
||||
#define MDB_IS_OPEN 0x01
|
||||
#define MDB_OPEN_INDEX 0x02
|
||||
#define MDB_DEL_INDEX 0x08
|
||||
#define MDB_RE_OPEN 0x10
|
||||
|
||||
MDB_dbi mi_dbis[MDB_NDB];
|
||||
};
|
||||
|
||||
#define mi_id2entry mi_dbis[MDB_ID2ENTRY]
|
||||
#define mi_dn2id mi_dbis[MDB_DN2ID]
|
||||
#define mi_ad2id mi_dbis[MDB_AD2ID]
|
||||
|
||||
typedef struct mdb_op_info {
|
||||
OpExtra moi_oe;
|
||||
MDB_txn* moi_txn;
|
||||
int moi_ref;
|
||||
char moi_flag;
|
||||
} mdb_op_info;
|
||||
#define MOI_READER 0x01
|
||||
#define MOI_FREEIT 0x02
|
||||
|
||||
/* Copy an ID "src" to pointer "dst" in big-endian byte order */
|
||||
#define MDB_ID2DISK( src, dst ) \
|
||||
do { int i0; ID tmp; unsigned char *_p; \
|
||||
tmp = (src); _p = (unsigned char *)(dst); \
|
||||
for ( i0=sizeof(ID)-1; i0>=0; i0-- ) { \
|
||||
_p[i0] = tmp & 0xff; tmp >>= 8; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* Copy a pointer "src" to a pointer "dst" from big-endian to native order */
|
||||
#define MDB_DISK2ID( src, dst ) \
|
||||
do { unsigned i0; ID tmp = 0; unsigned char *_p; \
|
||||
_p = (unsigned char *)(src); \
|
||||
for ( i0=0; i0<sizeof(ID); i0++ ) { \
|
||||
tmp <<= 8; tmp |= *_p++; \
|
||||
} *(dst) = tmp; \
|
||||
} while (0)
|
||||
|
||||
LDAP_END_DECL
|
||||
|
||||
/* for the cache of attribute information (which are indexed, etc.) */
|
||||
typedef struct mdb_attrinfo {
|
||||
AttributeDescription *ai_desc; /* attribute description cn;lang-en */
|
||||
slap_mask_t ai_indexmask; /* how the attr is indexed */
|
||||
slap_mask_t ai_newmask; /* new settings to replace old mask */
|
||||
#ifdef LDAP_COMP_MATCH
|
||||
ComponentReference* ai_cr; /*component indexing*/
|
||||
#endif
|
||||
int ai_idx; /* position in AI array */
|
||||
MDB_dbi ai_dbi;
|
||||
} AttrInfo;
|
||||
|
||||
/* These flags must not clash with SLAP_INDEX flags or ops in slap.h! */
|
||||
#define MDB_INDEX_DELETING 0x8000U /* index is being modified */
|
||||
#define MDB_INDEX_UPDATE_OP 0x03 /* performing an index update */
|
||||
|
||||
/* For slapindex to record which attrs in an entry belong to which
|
||||
* index database
|
||||
*/
|
||||
typedef struct AttrList {
|
||||
struct AttrList *next;
|
||||
Attribute *attr;
|
||||
} AttrList;
|
||||
|
||||
typedef struct IndexRec {
|
||||
AttrInfo *ai;
|
||||
AttrList *attrs;
|
||||
} IndexRec;
|
||||
|
||||
#include "proto-mdb.h"
|
||||
|
||||
#endif /* _BACK_MDB_H_ */
|
||||
156
servers/slapd/back-mdb/bind.c
Normal file
156
servers/slapd/back-mdb/bind.c
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
/* bind.c - mdb backend bind routine */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/unistd.h>
|
||||
|
||||
#include "back-mdb.h"
|
||||
|
||||
int
|
||||
mdb_bind( Operation *op, SlapReply *rs )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
|
||||
Entry *e;
|
||||
Attribute *a;
|
||||
|
||||
AttributeDescription *password = slap_schema.si_ad_userPassword;
|
||||
|
||||
MDB_txn *rtxn;
|
||||
mdb_op_info opinfo = {0}, *moi = &opinfo;
|
||||
|
||||
Debug( LDAP_DEBUG_ARGS,
|
||||
"==> " LDAP_XSTRING(mdb_bind) ": dn: %s\n",
|
||||
op->o_req_dn.bv_val, 0, 0);
|
||||
|
||||
/* allow noauth binds */
|
||||
switch ( be_rootdn_bind( op, NULL ) ) {
|
||||
case LDAP_SUCCESS:
|
||||
/* frontend will send result */
|
||||
return rs->sr_err = LDAP_SUCCESS;
|
||||
|
||||
default:
|
||||
/* give the database a chance */
|
||||
/* NOTE: this behavior departs from that of other backends,
|
||||
* since the others, in case of password checking failure
|
||||
* do not give the database a chance. If an entry with
|
||||
* rootdn's name does not exist in the database the result
|
||||
* will be the same. See ITS#4962 for discussion. */
|
||||
break;
|
||||
}
|
||||
|
||||
rs->sr_err = mdb_opinfo_get(op, mdb, 1, &moi);
|
||||
switch(rs->sr_err) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
rs->sr_text = "internal error";
|
||||
send_ldap_result( op, rs );
|
||||
return rs->sr_err;
|
||||
}
|
||||
|
||||
rtxn = moi->moi_txn;
|
||||
|
||||
/* get entry with reader lock */
|
||||
rs->sr_err = mdb_dn2entry( op, rtxn, &op->o_req_ndn, &e, 0 );
|
||||
|
||||
switch(rs->sr_err) {
|
||||
case MDB_NOTFOUND:
|
||||
rs->sr_err = LDAP_INVALID_CREDENTIALS;
|
||||
goto done;
|
||||
case 0:
|
||||
break;
|
||||
case LDAP_BUSY:
|
||||
rs->sr_text = "ldap_server_busy";
|
||||
goto done;
|
||||
default:
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto done;
|
||||
}
|
||||
|
||||
ber_dupbv( &op->oq_bind.rb_edn, &e->e_name );
|
||||
|
||||
/* check for deleted */
|
||||
if ( is_entry_subentry( e ) ) {
|
||||
/* entry is an subentry, don't allow bind */
|
||||
Debug( LDAP_DEBUG_TRACE, "entry is subentry\n", 0,
|
||||
0, 0 );
|
||||
rs->sr_err = LDAP_INVALID_CREDENTIALS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( is_entry_alias( e ) ) {
|
||||
/* entry is an alias, don't allow bind */
|
||||
Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0, 0, 0 );
|
||||
rs->sr_err = LDAP_INVALID_CREDENTIALS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( is_entry_referral( e ) ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
|
||||
0, 0 );
|
||||
rs->sr_err = LDAP_INVALID_CREDENTIALS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch ( op->oq_bind.rb_method ) {
|
||||
case LDAP_AUTH_SIMPLE:
|
||||
a = attr_find( e->e_attrs, password );
|
||||
if ( a == NULL ) {
|
||||
rs->sr_err = LDAP_INVALID_CREDENTIALS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( slap_passwd_check( op, e, a, &op->oq_bind.rb_cred,
|
||||
&rs->sr_text ) != 0 )
|
||||
{
|
||||
/* failure; stop front end from sending result */
|
||||
rs->sr_err = LDAP_INVALID_CREDENTIALS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
rs->sr_err = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 ); /* should not be reachable */
|
||||
rs->sr_err = LDAP_STRONG_AUTH_NOT_SUPPORTED;
|
||||
rs->sr_text = "authentication method not supported";
|
||||
}
|
||||
|
||||
done:
|
||||
if ( moi == &opinfo ) {
|
||||
mdb_txn_reset( moi->moi_txn );
|
||||
LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
|
||||
}
|
||||
/* free entry and reader lock */
|
||||
if( e != NULL ) {
|
||||
mdb_entry_return( e );
|
||||
}
|
||||
|
||||
if ( rs->sr_err ) {
|
||||
send_ldap_result( op, rs );
|
||||
if ( rs->sr_ref ) {
|
||||
ber_bvarray_free( rs->sr_ref );
|
||||
rs->sr_ref = NULL;
|
||||
}
|
||||
}
|
||||
/* front end will send result on success (rs->sr_err==0) */
|
||||
return rs->sr_err;
|
||||
}
|
||||
140
servers/slapd/back-mdb/compare.c
Normal file
140
servers/slapd/back-mdb/compare.c
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/* compare.c - mdb backend compare routine */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ac/string.h>
|
||||
|
||||
#include "back-mdb.h"
|
||||
|
||||
int
|
||||
mdb_compare( Operation *op, SlapReply *rs )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
|
||||
Entry *e = NULL;
|
||||
int manageDSAit = get_manageDSAit( op );
|
||||
|
||||
MDB_txn *rtxn;
|
||||
mdb_op_info opinfo = {0}, *moi = &opinfo;
|
||||
|
||||
rs->sr_err = mdb_opinfo_get(op, mdb, 1, &moi);
|
||||
switch(rs->sr_err) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
|
||||
return rs->sr_err;
|
||||
}
|
||||
|
||||
rtxn = moi->moi_txn;
|
||||
|
||||
/* get entry */
|
||||
rs->sr_err = mdb_dn2entry( op, rtxn, &op->o_req_ndn, &e, 1 );
|
||||
switch( rs->sr_err ) {
|
||||
case MDB_NOTFOUND:
|
||||
case 0:
|
||||
break;
|
||||
case LDAP_BUSY:
|
||||
rs->sr_text = "ldap server busy";
|
||||
goto return_results;
|
||||
default:
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
if ( rs->sr_err == MDB_NOTFOUND ) {
|
||||
if ( e != NULL ) {
|
||||
/* return referral only if "disclose" is granted on the object */
|
||||
if ( ! access_allowed( op, e, slap_schema.si_ad_entry,
|
||||
NULL, ACL_DISCLOSE, NULL ) )
|
||||
{
|
||||
rs->sr_err = LDAP_NO_SUCH_OBJECT;
|
||||
|
||||
} else {
|
||||
rs->sr_matched = ch_strdup( e->e_dn );
|
||||
if ( is_entry_referral( e )) {
|
||||
BerVarray ref = get_entry_referrals( op, e );
|
||||
rs->sr_ref = referral_rewrite( ref, &e->e_name,
|
||||
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
|
||||
ber_bvarray_free( ref );
|
||||
} else {
|
||||
rs->sr_ref = NULL;
|
||||
}
|
||||
rs->sr_err = LDAP_REFERRAL;
|
||||
}
|
||||
mdb_entry_return( e );
|
||||
e = NULL;
|
||||
|
||||
} else {
|
||||
rs->sr_ref = referral_rewrite( default_referral,
|
||||
NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
|
||||
rs->sr_err = rs->sr_ref ? LDAP_REFERRAL : LDAP_NO_SUCH_OBJECT;
|
||||
}
|
||||
|
||||
rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
|
||||
send_ldap_result( op, rs );
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!manageDSAit && is_entry_referral( e ) ) {
|
||||
/* return referral only if "disclose" is granted on the object */
|
||||
if ( !access_allowed( op, e, slap_schema.si_ad_entry,
|
||||
NULL, ACL_DISCLOSE, NULL ) )
|
||||
{
|
||||
rs->sr_err = LDAP_NO_SUCH_OBJECT;
|
||||
} else {
|
||||
/* entry is a referral, don't allow compare */
|
||||
rs->sr_ref = get_entry_referrals( op, e );
|
||||
rs->sr_err = LDAP_REFERRAL;
|
||||
rs->sr_matched = e->e_name.bv_val;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, 0, 0 );
|
||||
|
||||
send_ldap_result( op, rs );
|
||||
|
||||
ber_bvarray_free( rs->sr_ref );
|
||||
rs->sr_ref = NULL;
|
||||
rs->sr_matched = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
rs->sr_err = slap_compare_entry( op, e, op->orc_ava );
|
||||
|
||||
return_results:
|
||||
send_ldap_result( op, rs );
|
||||
|
||||
switch ( rs->sr_err ) {
|
||||
case LDAP_COMPARE_FALSE:
|
||||
case LDAP_COMPARE_TRUE:
|
||||
rs->sr_err = LDAP_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
if ( moi == &opinfo ) {
|
||||
mdb_txn_reset( moi->moi_txn );
|
||||
LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
|
||||
}
|
||||
/* free entry */
|
||||
if ( e != NULL ) {
|
||||
mdb_entry_return( e );
|
||||
}
|
||||
|
||||
return rs->sr_err;
|
||||
}
|
||||
588
servers/slapd/back-mdb/config.c
Normal file
588
servers/slapd/back-mdb/config.c
Normal file
|
|
@ -0,0 +1,588 @@
|
|||
/* config.c - mdb backend configuration file routine */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ac/ctype.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/errno.h>
|
||||
|
||||
#include "back-mdb.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "lutil.h"
|
||||
#include "ldap_rq.h"
|
||||
|
||||
static ConfigDriver mdb_cf_gen;
|
||||
|
||||
enum {
|
||||
MDB_CHKPT = 1,
|
||||
MDB_DIRECTORY,
|
||||
MDB_DBNOSYNC,
|
||||
MDB_INDEX,
|
||||
MDB_MAXREADERS,
|
||||
MDB_MAXSIZE,
|
||||
MDB_MODE,
|
||||
MDB_SSTACK,
|
||||
};
|
||||
|
||||
static ConfigTable mdbcfg[] = {
|
||||
{ "directory", "dir", 2, 2, 0, ARG_STRING|ARG_MAGIC|MDB_DIRECTORY,
|
||||
mdb_cf_gen, "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
|
||||
"DESC 'Directory for database content' "
|
||||
"EQUALITY caseIgnoreMatch "
|
||||
"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
|
||||
{ "checkpoint", "kbyte> <min", 3, 3, 0, ARG_MAGIC|MDB_CHKPT,
|
||||
mdb_cf_gen, "( OLcfgDbAt:1.2 NAME 'olcDbCheckpoint' "
|
||||
"DESC 'Database checkpoint interval in kbytes and minutes' "
|
||||
"SYNTAX OMsDirectoryString SINGLE-VALUE )",NULL, NULL },
|
||||
{ "dbnosync", NULL, 1, 2, 0, ARG_ON_OFF|ARG_MAGIC|MDB_DBNOSYNC,
|
||||
mdb_cf_gen, "( OLcfgDbAt:1.4 NAME 'olcDbNoSync' "
|
||||
"DESC 'Disable synchronous database writes' "
|
||||
"SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
|
||||
{ "index", "attr> <[pres,eq,approx,sub]", 2, 3, 0, ARG_MAGIC|MDB_INDEX,
|
||||
mdb_cf_gen, "( OLcfgDbAt:0.2 NAME 'olcDbIndex' "
|
||||
"DESC 'Attribute index parameters' "
|
||||
"EQUALITY caseIgnoreMatch "
|
||||
"SYNTAX OMsDirectoryString )", NULL, NULL },
|
||||
{ "maxreaders", "num", 2, 2, 0, ARG_INT|ARG_MAGIC|MDB_MAXREADERS,
|
||||
mdb_cf_gen, "( OLcfgDbAt:12.1 NAME 'olcDbMaxReaders' "
|
||||
"DESC 'Maximum number of threads that may access the DB concurrently' "
|
||||
"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
|
||||
{ "maxsize", "size", 2, 2, 0, ARG_ULONG|ARG_MAGIC|MDB_MAXSIZE,
|
||||
mdb_cf_gen, "( OLcfgDbAt:12.2 NAME 'olcDbMaxSize' "
|
||||
"DESC 'Maximum size of DB in bytes' "
|
||||
"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
|
||||
{ "mode", "mode", 2, 2, 0, ARG_MAGIC|MDB_MODE,
|
||||
mdb_cf_gen, "( OLcfgDbAt:0.3 NAME 'olcDbMode' "
|
||||
"DESC 'Unix permissions of database files' "
|
||||
"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
|
||||
{ "searchstack", "depth", 2, 2, 0, ARG_INT|ARG_MAGIC|MDB_SSTACK,
|
||||
mdb_cf_gen, "( OLcfgDbAt:1.9 NAME 'olcDbSearchStack' "
|
||||
"DESC 'Depth of search stack in IDLs' "
|
||||
"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
|
||||
{ NULL, NULL, 0, 0, 0, ARG_IGNORED,
|
||||
NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static ConfigOCs mdbocs[] = {
|
||||
{
|
||||
"( OLcfgDbOc:12.1 "
|
||||
"NAME 'olcMdbConfig' "
|
||||
"DESC 'MDB backend configuration' "
|
||||
"SUP olcDatabaseConfig "
|
||||
"MUST olcDbDirectory "
|
||||
"MAY ( olcDbCheckpoint $ "
|
||||
"olcDbNoSync $ olcDbIndex $ olcDbMaxReaders $ olcDbMaxsize $ "
|
||||
"olcDbMode $ olcDbSearchStack ) )",
|
||||
Cft_Database, mdbcfg },
|
||||
{ NULL, 0, NULL }
|
||||
};
|
||||
|
||||
/* perform periodic syncs */
|
||||
static void *
|
||||
mdb_checkpoint( void *ctx, void *arg )
|
||||
{
|
||||
struct re_s *rtask = arg;
|
||||
struct mdb_info *mdb = rtask->arg;
|
||||
|
||||
mdb_env_sync( mdb->mi_dbenv, 0 );
|
||||
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
|
||||
ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
|
||||
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* reindex entries on the fly */
|
||||
static void *
|
||||
mdb_online_index( void *ctx, void *arg )
|
||||
{
|
||||
struct re_s *rtask = arg;
|
||||
BackendDB *be = rtask->arg;
|
||||
struct mdb_info *mdb = be->be_private;
|
||||
|
||||
Connection conn = {0};
|
||||
OperationBuffer opbuf;
|
||||
Operation *op;
|
||||
|
||||
MDB_cursor *curs;
|
||||
MDB_val key, data;
|
||||
MDB_txn *txn;
|
||||
ID id;
|
||||
Entry *e;
|
||||
int rc, getnext = 1;
|
||||
int i;
|
||||
|
||||
connection_fake_init( &conn, &opbuf, ctx );
|
||||
op = &opbuf.ob_op;
|
||||
|
||||
op->o_bd = be;
|
||||
|
||||
id = 1;
|
||||
key.mv_data = &id;
|
||||
key.mv_size = sizeof(ID);
|
||||
|
||||
while ( 1 ) {
|
||||
if ( slapd_shutdown )
|
||||
break;
|
||||
|
||||
rc = mdb_txn_begin( mdb->mi_dbenv, 0, &txn );
|
||||
if ( rc )
|
||||
break;
|
||||
if ( getnext ) {
|
||||
getnext = 0;
|
||||
rc = mdb_cursor_open( txn, mdb->mi_id2entry, &curs );
|
||||
if ( rc ) {
|
||||
mdb_txn_abort( txn );
|
||||
break;
|
||||
}
|
||||
rc = mdb_cursor_get( curs, &key, &data, MDB_SET_RANGE );
|
||||
memcpy( &id, key.mv_data, sizeof( id ));
|
||||
mdb_cursor_close( curs );
|
||||
if ( rc ) {
|
||||
mdb_txn_abort( txn );
|
||||
if ( rc == MDB_NOTFOUND )
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = mdb_id2entry( op, txn, id, &e );
|
||||
if ( rc ) {
|
||||
mdb_txn_abort( txn );
|
||||
if ( rc == MDB_NOTFOUND ) {
|
||||
id++;
|
||||
getnext = 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
rc = mdb_index_entry( op, txn, MDB_INDEX_UPDATE_OP, e );
|
||||
if ( rc == 0 ) {
|
||||
rc = mdb_txn_commit( txn );
|
||||
txn = NULL;
|
||||
}
|
||||
if ( rc )
|
||||
break;
|
||||
id++;
|
||||
getnext = 1;
|
||||
}
|
||||
|
||||
for ( i = 0; i < mdb->mi_nattrs; i++ ) {
|
||||
if ( mdb->mi_attrs[ i ]->ai_indexmask & MDB_INDEX_DELETING
|
||||
|| mdb->mi_attrs[ i ]->ai_newmask == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
mdb->mi_attrs[ i ]->ai_indexmask = mdb->mi_attrs[ i ]->ai_newmask;
|
||||
mdb->mi_attrs[ i ]->ai_newmask = 0;
|
||||
}
|
||||
|
||||
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
|
||||
ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
|
||||
mdb->mi_index_task = NULL;
|
||||
ldap_pvt_runqueue_remove( &slapd_rq, rtask );
|
||||
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Cleanup loose ends after Modify completes */
|
||||
static int
|
||||
mdb_cf_cleanup( ConfigArgs *c )
|
||||
{
|
||||
struct mdb_info *mdb = c->be->be_private;
|
||||
int rc = 0;
|
||||
|
||||
if ( mdb->mi_flags & MDB_DEL_INDEX ) {
|
||||
mdb_attr_flush( mdb );
|
||||
mdb->mi_flags ^= MDB_DEL_INDEX;
|
||||
}
|
||||
|
||||
if ( mdb->mi_flags & MDB_RE_OPEN ) {
|
||||
mdb->mi_flags ^= MDB_RE_OPEN;
|
||||
rc = c->be->bd_info->bi_db_close( c->be, &c->reply );
|
||||
if ( rc == 0 )
|
||||
rc = c->be->bd_info->bi_db_open( c->be, &c->reply );
|
||||
/* If this fails, we need to restart */
|
||||
if ( rc ) {
|
||||
slapd_shutdown = 2;
|
||||
snprintf( c->cr_msg, sizeof( c->cr_msg ),
|
||||
"failed to reopen database, rc=%d", rc );
|
||||
Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_cf_cleanup)
|
||||
": %s\n", c->cr_msg, 0, 0 );
|
||||
rc = LDAP_OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
if ( mdb->mi_flags & MDB_OPEN_INDEX ) {
|
||||
rc = mdb_attr_dbs_open( c->be, NULL, &c->reply );
|
||||
if ( rc )
|
||||
rc = LDAP_OTHER;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
mdb_cf_gen( ConfigArgs *c )
|
||||
{
|
||||
struct mdb_info *mdb = c->be->be_private;
|
||||
int rc;
|
||||
|
||||
if ( c->op == SLAP_CONFIG_EMIT ) {
|
||||
rc = 0;
|
||||
switch( c->type ) {
|
||||
case MDB_MODE: {
|
||||
char buf[64];
|
||||
struct berval bv;
|
||||
bv.bv_len = snprintf( buf, sizeof(buf), "0%o", mdb->mi_dbenv_mode );
|
||||
if ( bv.bv_len > 0 && bv.bv_len < sizeof(buf) ) {
|
||||
bv.bv_val = buf;
|
||||
value_add_one( &c->rvalue_vals, &bv );
|
||||
} else {
|
||||
rc = 1;
|
||||
}
|
||||
} break;
|
||||
|
||||
case MDB_CHKPT:
|
||||
if ( mdb->mi_txn_cp ) {
|
||||
char buf[64];
|
||||
struct berval bv;
|
||||
bv.bv_len = snprintf( buf, sizeof(buf), "%ld %ld",
|
||||
(long) mdb->mi_txn_cp_kbyte, (long) mdb->mi_txn_cp_min );
|
||||
if ( bv.bv_len > 0 && bv.bv_len < sizeof(buf) ) {
|
||||
bv.bv_val = buf;
|
||||
value_add_one( &c->rvalue_vals, &bv );
|
||||
} else {
|
||||
rc = 1;
|
||||
}
|
||||
} else {
|
||||
rc = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case MDB_DIRECTORY:
|
||||
if ( mdb->mi_dbenv_home ) {
|
||||
c->value_string = ch_strdup( mdb->mi_dbenv_home );
|
||||
} else {
|
||||
rc = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case MDB_DBNOSYNC:
|
||||
if ( mdb->mi_dbenv_flags & MDB_NOSYNC )
|
||||
c->value_int = 1;
|
||||
break;
|
||||
|
||||
case MDB_INDEX:
|
||||
mdb_attr_index_unparse( mdb, &c->rvalue_vals );
|
||||
if ( !c->rvalue_vals ) rc = 1;
|
||||
break;
|
||||
|
||||
case MDB_SSTACK:
|
||||
c->value_int = mdb->mi_search_stack_depth;
|
||||
break;
|
||||
|
||||
case MDB_MAXREADERS:
|
||||
c->value_int = mdb->mi_readers;
|
||||
break;
|
||||
|
||||
case MDB_MAXSIZE:
|
||||
c->value_ulong = mdb->mi_mapsize;
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
} else if ( c->op == LDAP_MOD_DELETE ) {
|
||||
rc = 0;
|
||||
switch( c->type ) {
|
||||
case MDB_MODE:
|
||||
#if 0
|
||||
/* FIXME: does it make any sense to change the mode,
|
||||
* if we don't exec a chmod()? */
|
||||
mdb->bi_dbenv_mode = SLAPD_DEFAULT_DB_MODE;
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* single-valued no-ops */
|
||||
case MDB_SSTACK:
|
||||
case MDB_MAXREADERS:
|
||||
case MDB_MAXSIZE:
|
||||
break;
|
||||
|
||||
case MDB_CHKPT:
|
||||
if ( mdb->mi_txn_cp_task ) {
|
||||
struct re_s *re = mdb->mi_txn_cp_task;
|
||||
mdb->mi_txn_cp_task = NULL;
|
||||
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
|
||||
if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
|
||||
ldap_pvt_runqueue_stoptask( &slapd_rq, re );
|
||||
ldap_pvt_runqueue_remove( &slapd_rq, re );
|
||||
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
|
||||
}
|
||||
mdb->mi_txn_cp = 0;
|
||||
break;
|
||||
case MDB_DIRECTORY:
|
||||
mdb->mi_flags |= MDB_RE_OPEN;
|
||||
ch_free( mdb->mi_dbenv_home );
|
||||
mdb->mi_dbenv_home = NULL;
|
||||
c->cleanup = mdb_cf_cleanup;
|
||||
ldap_pvt_thread_pool_purgekey( mdb->mi_dbenv );
|
||||
break;
|
||||
case MDB_DBNOSYNC:
|
||||
mdb_env_set_flags( mdb->mi_dbenv, MDB_NOSYNC, 0 );
|
||||
break;
|
||||
case MDB_INDEX:
|
||||
if ( c->valx == -1 ) {
|
||||
int i;
|
||||
|
||||
/* delete all (FIXME) */
|
||||
for ( i = 0; i < mdb->mi_nattrs; i++ ) {
|
||||
mdb->mi_attrs[i]->ai_indexmask |= MDB_INDEX_DELETING;
|
||||
}
|
||||
mdb->mi_flags |= MDB_DEL_INDEX;
|
||||
c->cleanup = mdb_cf_cleanup;
|
||||
|
||||
} else {
|
||||
struct berval bv, def = BER_BVC("default");
|
||||
char *ptr;
|
||||
|
||||
for (ptr = c->line; !isspace( (unsigned char) *ptr ); ptr++);
|
||||
|
||||
bv.bv_val = c->line;
|
||||
bv.bv_len = ptr - bv.bv_val;
|
||||
if ( bvmatch( &bv, &def )) {
|
||||
mdb->mi_defaultmask = 0;
|
||||
|
||||
} else {
|
||||
int i;
|
||||
char **attrs;
|
||||
char sep;
|
||||
|
||||
sep = bv.bv_val[ bv.bv_len ];
|
||||
bv.bv_val[ bv.bv_len ] = '\0';
|
||||
attrs = ldap_str2charray( bv.bv_val, "," );
|
||||
|
||||
for ( i = 0; attrs[ i ]; i++ ) {
|
||||
AttributeDescription *ad = NULL;
|
||||
const char *text;
|
||||
AttrInfo *ai;
|
||||
|
||||
slap_str2ad( attrs[ i ], &ad, &text );
|
||||
/* if we got here... */
|
||||
assert( ad != NULL );
|
||||
|
||||
ai = mdb_attr_mask( mdb, ad );
|
||||
/* if we got here... */
|
||||
assert( ai != NULL );
|
||||
|
||||
ai->ai_indexmask |= MDB_INDEX_DELETING;
|
||||
mdb->mi_flags |= MDB_DEL_INDEX;
|
||||
c->cleanup = mdb_cf_cleanup;
|
||||
}
|
||||
|
||||
bv.bv_val[ bv.bv_len ] = sep;
|
||||
ldap_charray_free( attrs );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
switch( c->type ) {
|
||||
case MDB_MODE:
|
||||
if ( ASCII_DIGIT( c->argv[1][0] ) ) {
|
||||
long mode;
|
||||
char *next;
|
||||
errno = 0;
|
||||
mode = strtol( c->argv[1], &next, 0 );
|
||||
if ( errno != 0 || next == c->argv[1] || next[0] != '\0' ) {
|
||||
fprintf( stderr, "%s: "
|
||||
"unable to parse mode=\"%s\".\n",
|
||||
c->log, c->argv[1] );
|
||||
return 1;
|
||||
}
|
||||
mdb->mi_dbenv_mode = mode;
|
||||
|
||||
} else {
|
||||
char *m = c->argv[1];
|
||||
int who, what, mode = 0;
|
||||
|
||||
if ( strlen( m ) != STRLENOF("-rwxrwxrwx") ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( m[0] != '-' ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
m++;
|
||||
for ( who = 0; who < 3; who++ ) {
|
||||
for ( what = 0; what < 3; what++, m++ ) {
|
||||
if ( m[0] == '-' ) {
|
||||
continue;
|
||||
} else if ( m[0] != "rwx"[what] ) {
|
||||
return 1;
|
||||
}
|
||||
mode += ((1 << (2 - what)) << 3*(2 - who));
|
||||
}
|
||||
}
|
||||
mdb->mi_dbenv_mode = mode;
|
||||
}
|
||||
break;
|
||||
case MDB_CHKPT: {
|
||||
long l;
|
||||
mdb->mi_txn_cp = 1;
|
||||
if ( lutil_atolx( &l, c->argv[1], 0 ) != 0 ) {
|
||||
fprintf( stderr, "%s: "
|
||||
"invalid kbyte \"%s\" in \"checkpoint\".\n",
|
||||
c->log, c->argv[1] );
|
||||
return 1;
|
||||
}
|
||||
mdb->mi_txn_cp_kbyte = l;
|
||||
if ( lutil_atolx( &l, c->argv[2], 0 ) != 0 ) {
|
||||
fprintf( stderr, "%s: "
|
||||
"invalid minutes \"%s\" in \"checkpoint\".\n",
|
||||
c->log, c->argv[2] );
|
||||
return 1;
|
||||
}
|
||||
mdb->mi_txn_cp_min = l;
|
||||
/* If we're in server mode and time-based checkpointing is enabled,
|
||||
* submit a task to perform periodic checkpoints.
|
||||
*/
|
||||
if ((slapMode & SLAP_SERVER_MODE) && mdb->mi_txn_cp_min ) {
|
||||
struct re_s *re = mdb->mi_txn_cp_task;
|
||||
if ( re ) {
|
||||
re->interval.tv_sec = mdb->mi_txn_cp_min * 60;
|
||||
} else {
|
||||
if ( c->be->be_suffix == NULL || BER_BVISNULL( &c->be->be_suffix[0] ) ) {
|
||||
fprintf( stderr, "%s: "
|
||||
"\"checkpoint\" must occur after \"suffix\".\n",
|
||||
c->log );
|
||||
return 1;
|
||||
}
|
||||
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
|
||||
mdb->mi_txn_cp_task = ldap_pvt_runqueue_insert( &slapd_rq,
|
||||
mdb->mi_txn_cp_min * 60, mdb_checkpoint, mdb,
|
||||
LDAP_XSTRING(mdb_checkpoint), c->be->be_suffix[0].bv_val );
|
||||
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case MDB_DIRECTORY: {
|
||||
FILE *f;
|
||||
char *ptr, *testpath;
|
||||
int len;
|
||||
|
||||
len = strlen( c->value_string );
|
||||
testpath = ch_malloc( len + STRLENOF(LDAP_DIRSEP) + STRLENOF("DUMMY") + 1 );
|
||||
ptr = lutil_strcopy( testpath, c->value_string );
|
||||
*ptr++ = LDAP_DIRSEP[0];
|
||||
strcpy( ptr, "DUMMY" );
|
||||
f = fopen( testpath, "w" );
|
||||
if ( f ) {
|
||||
fclose( f );
|
||||
unlink( testpath );
|
||||
}
|
||||
ch_free( testpath );
|
||||
if ( !f ) {
|
||||
snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: invalid path: %s",
|
||||
c->log, strerror( errno ));
|
||||
Debug( LDAP_DEBUG_ANY, "%s\n", c->cr_msg, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( mdb->mi_dbenv_home )
|
||||
ch_free( mdb->mi_dbenv_home );
|
||||
mdb->mi_dbenv_home = c->value_string;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case MDB_DBNOSYNC:
|
||||
if ( c->value_int )
|
||||
mdb->mi_dbenv_flags |= MDB_NOSYNC;
|
||||
else
|
||||
mdb->mi_dbenv_flags ^= MDB_NOSYNC;
|
||||
if ( mdb->mi_flags & MDB_IS_OPEN ) {
|
||||
mdb_env_set_flags( mdb->mi_dbenv, MDB_NOSYNC,
|
||||
c->value_int );
|
||||
}
|
||||
break;
|
||||
|
||||
case MDB_INDEX:
|
||||
rc = mdb_attr_index_config( mdb, c->fname, c->lineno,
|
||||
c->argc - 1, &c->argv[1], &c->reply);
|
||||
|
||||
if( rc != LDAP_SUCCESS ) return 1;
|
||||
c->cleanup = mdb_cf_cleanup;
|
||||
mdb->mi_flags |= MDB_OPEN_INDEX;
|
||||
if (( mdb->mi_flags & MDB_IS_OPEN ) && !mdb->mi_index_task ) {
|
||||
/* Start the task as soon as we finish here. Set a long
|
||||
* interval (10 hours) so that it only gets scheduled once.
|
||||
*/
|
||||
if ( c->be->be_suffix == NULL || BER_BVISNULL( &c->be->be_suffix[0] ) ) {
|
||||
fprintf( stderr, "%s: "
|
||||
"\"index\" must occur after \"suffix\".\n",
|
||||
c->log );
|
||||
return 1;
|
||||
}
|
||||
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
|
||||
mdb->mi_index_task = ldap_pvt_runqueue_insert( &slapd_rq, 36000,
|
||||
mdb_online_index, c->be,
|
||||
LDAP_XSTRING(mdb_online_index), c->be->be_suffix[0].bv_val );
|
||||
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
|
||||
}
|
||||
break;
|
||||
|
||||
case MDB_SSTACK:
|
||||
if ( c->value_int < MINIMUM_SEARCH_STACK_DEPTH ) {
|
||||
fprintf( stderr,
|
||||
"%s: depth %d too small, using %d\n",
|
||||
c->log, c->value_int, MINIMUM_SEARCH_STACK_DEPTH );
|
||||
c->value_int = MINIMUM_SEARCH_STACK_DEPTH;
|
||||
}
|
||||
mdb->mi_search_stack_depth = c->value_int;
|
||||
break;
|
||||
|
||||
case MDB_MAXREADERS:
|
||||
mdb->mi_readers = c->value_int;
|
||||
if ( mdb->mi_flags & MDB_IS_OPEN )
|
||||
mdb->mi_flags |= MDB_RE_OPEN;
|
||||
break;
|
||||
|
||||
case MDB_MAXSIZE:
|
||||
mdb->mi_mapsize = c->value_ulong;
|
||||
if ( mdb->mi_flags & MDB_IS_OPEN )
|
||||
mdb->mi_flags |= MDB_RE_OPEN;
|
||||
break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdb_back_init_cf( BackendInfo *bi )
|
||||
{
|
||||
int rc;
|
||||
bi->bi_cf_ocs = mdbocs;
|
||||
|
||||
rc = config_register_schema( mdbcfg, mdbocs );
|
||||
if ( rc ) return rc;
|
||||
return 0;
|
||||
}
|
||||
470
servers/slapd/back-mdb/delete.c
Normal file
470
servers/slapd/back-mdb/delete.c
Normal file
|
|
@ -0,0 +1,470 @@
|
|||
/* delete.c - mdb backend delete routine */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ac/string.h>
|
||||
|
||||
#include "lutil.h"
|
||||
#include "back-mdb.h"
|
||||
|
||||
int
|
||||
mdb_delete( Operation *op, SlapReply *rs )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
|
||||
struct berval pdn = {0, NULL};
|
||||
Entry *e = NULL;
|
||||
Entry *p = NULL;
|
||||
int manageDSAit = get_manageDSAit( op );
|
||||
AttributeDescription *children = slap_schema.si_ad_children;
|
||||
AttributeDescription *entry = slap_schema.si_ad_entry;
|
||||
MDB_txn *txn = NULL;
|
||||
mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;
|
||||
|
||||
LDAPControl **preread_ctrl = NULL;
|
||||
LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
|
||||
int num_ctrls = 0;
|
||||
|
||||
int parent_is_glue = 0;
|
||||
int parent_is_leaf = 0;
|
||||
|
||||
#ifdef LDAP_X_TXN
|
||||
int settle = 0;
|
||||
#endif
|
||||
|
||||
Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(mdb_delete) ": %s\n",
|
||||
op->o_req_dn.bv_val, 0, 0 );
|
||||
|
||||
#ifdef LDAP_X_TXN
|
||||
if( op->o_txnSpec ) {
|
||||
/* acquire connection lock */
|
||||
ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
|
||||
if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
|
||||
rs->sr_text = "invalid transaction identifier";
|
||||
rs->sr_err = LDAP_X_TXN_ID_INVALID;
|
||||
goto txnReturn;
|
||||
} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
|
||||
settle=1;
|
||||
goto txnReturn;
|
||||
}
|
||||
|
||||
if( op->o_conn->c_txn_backend == NULL ) {
|
||||
op->o_conn->c_txn_backend = op->o_bd;
|
||||
|
||||
} else if( op->o_conn->c_txn_backend != op->o_bd ) {
|
||||
rs->sr_text = "transaction cannot span multiple database contexts";
|
||||
rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
|
||||
goto txnReturn;
|
||||
}
|
||||
|
||||
/* insert operation into transaction */
|
||||
|
||||
rs->sr_text = "transaction specified";
|
||||
rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
|
||||
|
||||
txnReturn:
|
||||
/* release connection lock */
|
||||
ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
|
||||
|
||||
if( !settle ) {
|
||||
send_ldap_result( op, rs );
|
||||
return rs->sr_err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ctrls[num_ctrls] = 0;
|
||||
|
||||
/* allocate CSN */
|
||||
if ( BER_BVISNULL( &op->o_csn ) ) {
|
||||
struct berval csn;
|
||||
char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
|
||||
|
||||
csn.bv_val = csnbuf;
|
||||
csn.bv_len = sizeof(csnbuf);
|
||||
slap_get_csn( op, &csn, 1 );
|
||||
}
|
||||
|
||||
/* begin transaction */
|
||||
rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi );
|
||||
rs->sr_text = NULL;
|
||||
if( rs->sr_err != 0 ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_delete) ": txn_begin failed: "
|
||||
"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
txn = moi->moi_txn;
|
||||
|
||||
if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
|
||||
dnParent( &op->o_req_ndn, &pdn );
|
||||
}
|
||||
|
||||
/* get parent */
|
||||
rs->sr_err = mdb_dn2entry( op, txn, &pdn, &p, 1 );
|
||||
switch( rs->sr_err ) {
|
||||
case 0:
|
||||
case MDB_NOTFOUND:
|
||||
break;
|
||||
case LDAP_BUSY:
|
||||
rs->sr_text = "ldap server busy";
|
||||
goto return_results;
|
||||
default:
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
if ( rs->sr_err == MDB_NOTFOUND ) {
|
||||
Debug( LDAP_DEBUG_ARGS,
|
||||
"<=- " LDAP_XSTRING(mdb_delete) ": no such object %s\n",
|
||||
op->o_req_dn.bv_val, 0, 0);
|
||||
|
||||
if ( p && !BER_BVISEMPTY( &p->e_name )) {
|
||||
rs->sr_matched = ch_strdup( p->e_name.bv_val );
|
||||
if ( is_entry_referral( p )) {
|
||||
BerVarray ref = get_entry_referrals( op, p );
|
||||
rs->sr_ref = referral_rewrite( ref, &p->e_name,
|
||||
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
|
||||
ber_bvarray_free( ref );
|
||||
} else {
|
||||
rs->sr_ref = NULL;
|
||||
}
|
||||
} else {
|
||||
rs->sr_ref = referral_rewrite( default_referral, NULL,
|
||||
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
|
||||
}
|
||||
if ( p ) {
|
||||
mdb_entry_return( p );
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
rs->sr_err = LDAP_REFERRAL;
|
||||
rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* get entry */
|
||||
rs->sr_err = mdb_dn2entry( op, txn, &op->o_req_ndn, &e, 0 );
|
||||
switch( rs->sr_err ) {
|
||||
case MDB_NOTFOUND:
|
||||
e = p;
|
||||
p = NULL;
|
||||
case 0:
|
||||
break;
|
||||
case LDAP_BUSY:
|
||||
rs->sr_text = "ldap server busy";
|
||||
goto return_results;
|
||||
default:
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* FIXME : dn2entry() should return non-glue entry */
|
||||
if ( rs->sr_err == MDB_NOTFOUND || ( !manageDSAit && is_entry_glue( e ))) {
|
||||
Debug( LDAP_DEBUG_ARGS,
|
||||
"<=- " LDAP_XSTRING(mdb_delete) ": no such object %s\n",
|
||||
op->o_req_dn.bv_val, 0, 0);
|
||||
|
||||
rs->sr_matched = ch_strdup( e->e_dn );
|
||||
if ( is_entry_referral( e )) {
|
||||
BerVarray ref = get_entry_referrals( op, e );
|
||||
rs->sr_ref = referral_rewrite( ref, &e->e_name,
|
||||
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
|
||||
ber_bvarray_free( ref );
|
||||
} else {
|
||||
rs->sr_ref = NULL;
|
||||
}
|
||||
mdb_entry_return( e );
|
||||
e = NULL;
|
||||
|
||||
rs->sr_err = LDAP_REFERRAL;
|
||||
rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
if ( pdn.bv_len != 0 ) {
|
||||
/* check parent for "children" acl */
|
||||
rs->sr_err = access_allowed( op, p,
|
||||
children, NULL, ACL_WDEL, NULL );
|
||||
|
||||
if ( !rs->sr_err ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_delete) ": no write "
|
||||
"access to parent\n", 0, 0, 0 );
|
||||
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
||||
rs->sr_text = "no write access to parent";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* no parent, must be root to delete */
|
||||
if( ! be_isroot( op ) ) {
|
||||
if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
|
||||
|| be_shadow_update( op ) ) {
|
||||
p = (Entry *)&slap_entry_root;
|
||||
|
||||
/* check parent for "children" acl */
|
||||
rs->sr_err = access_allowed( op, p,
|
||||
children, NULL, ACL_WDEL, NULL );
|
||||
|
||||
p = NULL;
|
||||
|
||||
if ( !rs->sr_err ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_delete)
|
||||
": no access to parent\n",
|
||||
0, 0, 0 );
|
||||
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
||||
rs->sr_text = "no write access to parent";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
} else {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_delete)
|
||||
": no parent and not root\n", 0, 0, 0 );
|
||||
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
||||
goto return_results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( get_assert( op ) &&
|
||||
( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
|
||||
{
|
||||
rs->sr_err = LDAP_ASSERTION_FAILED;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
rs->sr_err = access_allowed( op, e,
|
||||
entry, NULL, ACL_WDEL, NULL );
|
||||
|
||||
if ( !rs->sr_err ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_delete) ": no write access "
|
||||
"to entry\n", 0, 0, 0 );
|
||||
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
||||
rs->sr_text = "no write access to entry";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
if ( !manageDSAit && is_entry_referral( e ) ) {
|
||||
/* entry is a referral, don't allow delete */
|
||||
rs->sr_ref = get_entry_referrals( op, e );
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_delete) ": entry is referral\n",
|
||||
0, 0, 0 );
|
||||
|
||||
rs->sr_err = LDAP_REFERRAL;
|
||||
rs->sr_matched = ch_strdup( e->e_name.bv_val );
|
||||
rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* pre-read */
|
||||
if( op->o_preread ) {
|
||||
if( preread_ctrl == NULL ) {
|
||||
preread_ctrl = &ctrls[num_ctrls++];
|
||||
ctrls[num_ctrls] = NULL;
|
||||
}
|
||||
if( slap_read_controls( op, rs, e,
|
||||
&slap_pre_read_bv, preread_ctrl ) )
|
||||
{
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_delete) ": pre-read "
|
||||
"failed!\n", 0, 0, 0 );
|
||||
if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
|
||||
/* FIXME: is it correct to abort
|
||||
* operation if control fails? */
|
||||
goto return_results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rs->sr_text = NULL;
|
||||
|
||||
/* Can't do it if we have kids */
|
||||
rs->sr_err = mdb_dn2id_children( op, txn, e );
|
||||
if( rs->sr_err != MDB_NOTFOUND ) {
|
||||
switch( rs->sr_err ) {
|
||||
case 0:
|
||||
Debug(LDAP_DEBUG_ARGS,
|
||||
"<=- " LDAP_XSTRING(mdb_delete)
|
||||
": non-leaf %s\n",
|
||||
op->o_req_dn.bv_val, 0, 0);
|
||||
rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
|
||||
rs->sr_text = "subordinate objects must be deleted first";
|
||||
break;
|
||||
default:
|
||||
Debug(LDAP_DEBUG_ARGS,
|
||||
"<=- " LDAP_XSTRING(mdb_delete)
|
||||
": has_children failed: %s (%d)\n",
|
||||
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
}
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* delete from dn2id */
|
||||
rs->sr_err = mdb_dn2id_delete( op, txn, p->e_id, e );
|
||||
if ( rs->sr_err != 0 ) {
|
||||
Debug(LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_delete) ": dn2id failed: "
|
||||
"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
rs->sr_text = "DN index delete failed";
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* delete indices for old attributes */
|
||||
rs->sr_err = mdb_index_entry_del( op, txn, e );
|
||||
if ( rs->sr_err != LDAP_SUCCESS ) {
|
||||
Debug(LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_delete) ": index failed: "
|
||||
"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
rs->sr_text = "entry index delete failed";
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* fixup delete CSN */
|
||||
if ( !SLAP_SHADOW( op->o_bd )) {
|
||||
struct berval vals[2];
|
||||
|
||||
assert( !BER_BVISNULL( &op->o_csn ) );
|
||||
vals[0] = op->o_csn;
|
||||
BER_BVZERO( &vals[1] );
|
||||
rs->sr_err = mdb_index_values( op, txn, slap_schema.si_ad_entryCSN,
|
||||
vals, 0, SLAP_INDEX_ADD_OP );
|
||||
if ( rs->sr_err != LDAP_SUCCESS ) {
|
||||
rs->sr_text = "entryCSN index update failed";
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
goto return_results;
|
||||
}
|
||||
}
|
||||
|
||||
/* delete from id2entry */
|
||||
rs->sr_err = mdb_id2entry_delete( op->o_bd, txn, e );
|
||||
if ( rs->sr_err != 0 ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_delete) ": id2entry failed: "
|
||||
"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
rs->sr_text = "entry delete failed";
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
if ( pdn.bv_len != 0 ) {
|
||||
parent_is_glue = is_entry_glue(p);
|
||||
rs->sr_err = mdb_dn2id_children( op, txn, p );
|
||||
if ( rs->sr_err != MDB_NOTFOUND ) {
|
||||
switch( rs->sr_err ) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
Debug(LDAP_DEBUG_ARGS,
|
||||
"<=- " LDAP_XSTRING(mdb_delete)
|
||||
": has_children failed: %s (%d)\n",
|
||||
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
parent_is_leaf = 1;
|
||||
}
|
||||
mdb_entry_return( p );
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
if( moi == &opinfo ) {
|
||||
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
|
||||
opinfo.moi_oe.oe_key = NULL;
|
||||
if( op->o_noop ) {
|
||||
mdb_txn_abort( txn );
|
||||
rs->sr_err = LDAP_X_NO_OPERATION;
|
||||
txn = NULL;
|
||||
goto return_results;
|
||||
} else {
|
||||
rs->sr_err = mdb_txn_commit( txn );
|
||||
}
|
||||
txn = NULL;
|
||||
}
|
||||
|
||||
if( rs->sr_err != 0 ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_delete) ": txn_%s failed: %s (%d)\n",
|
||||
op->o_noop ? "abort (no-op)" : "commit",
|
||||
mdb_strerror(rs->sr_err), rs->sr_err );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "commit failed";
|
||||
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_delete) ": deleted%s id=%08lx dn=\"%s\"\n",
|
||||
op->o_noop ? " (no-op)" : "",
|
||||
e->e_id, op->o_req_dn.bv_val );
|
||||
rs->sr_err = LDAP_SUCCESS;
|
||||
rs->sr_text = NULL;
|
||||
if( num_ctrls ) rs->sr_ctrls = ctrls;
|
||||
|
||||
return_results:
|
||||
if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
|
||||
op->o_delete_glue_parent = 1;
|
||||
}
|
||||
|
||||
if ( p != NULL ) {
|
||||
mdb_entry_return( p );
|
||||
}
|
||||
|
||||
/* free entry */
|
||||
if( e != NULL ) {
|
||||
mdb_entry_return( e );
|
||||
}
|
||||
|
||||
if( moi == &opinfo ) {
|
||||
if( txn != NULL ) {
|
||||
mdb_txn_abort( txn );
|
||||
}
|
||||
if ( opinfo.moi_oe.oe_key ) {
|
||||
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
|
||||
}
|
||||
}
|
||||
|
||||
send_ldap_result( op, rs );
|
||||
slap_graduate_commit_csn( op );
|
||||
|
||||
if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
|
||||
slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
|
||||
slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
|
||||
}
|
||||
|
||||
#if 0
|
||||
if( rs->sr_err == LDAP_SUCCESS && mdb->bi_txn_cp_kbyte ) {
|
||||
TXN_CHECKPOINT( mdb->bi_dbenv,
|
||||
mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
|
||||
}
|
||||
#endif
|
||||
return rs->sr_err;
|
||||
}
|
||||
64
servers/slapd/back-mdb/dn2entry.c
Normal file
64
servers/slapd/back-mdb/dn2entry.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/* dn2entry.c - routines to deal with the dn2id / id2entry glue */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ac/string.h>
|
||||
|
||||
#include "back-mdb.h"
|
||||
|
||||
/*
|
||||
* dn2entry - look up dn in the cache/indexes and return the corresponding
|
||||
* entry. If the requested DN is not found and matched is TRUE, return info
|
||||
* for the closest ancestor of the DN. Otherwise e is NULL.
|
||||
*/
|
||||
|
||||
int
|
||||
mdb_dn2entry(
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
struct berval *dn,
|
||||
Entry **e,
|
||||
int matched )
|
||||
{
|
||||
int rc, rc2;
|
||||
ID id = NOID;
|
||||
struct berval mbv, nmbv;
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE, "mdb_dn2entry(\"%s\")\n",
|
||||
dn->bv_val, 0, 0 );
|
||||
|
||||
*e = NULL;
|
||||
|
||||
rc = mdb_dn2id( op, tid, dn, &id, &mbv, &nmbv );
|
||||
if ( rc ) {
|
||||
if ( matched )
|
||||
rc2 = mdb_id2entry( op, tid, id, e );
|
||||
|
||||
} else {
|
||||
rc = mdb_id2entry( op, tid, id, e );
|
||||
}
|
||||
if ( *e ) {
|
||||
(*e)->e_name = mbv;
|
||||
if ( rc == MDB_SUCCESS )
|
||||
ber_dupbv_x( &(*e)->e_nname, dn, op->o_tmpmemctx );
|
||||
else
|
||||
ber_dupbv_x( &(*e)->e_nname, &nmbv, op->o_tmpmemctx );
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
1083
servers/slapd/back-mdb/dn2id.c
Normal file
1083
servers/slapd/back-mdb/dn2id.c
Normal file
File diff suppressed because it is too large
Load diff
54
servers/slapd/back-mdb/extended.c
Normal file
54
servers/slapd/back-mdb/extended.c
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/* extended.c - mdb backend extended routines */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ac/string.h>
|
||||
|
||||
#include "back-mdb.h"
|
||||
#include "lber_pvt.h"
|
||||
|
||||
static struct exop {
|
||||
struct berval *oid;
|
||||
BI_op_extended *extended;
|
||||
} exop_table[] = {
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
int
|
||||
mdb_extended( Operation *op, SlapReply *rs )
|
||||
/* struct berval *reqoid,
|
||||
struct berval *reqdata,
|
||||
char **rspoid,
|
||||
struct berval **rspdata,
|
||||
LDAPControl *** rspctrls,
|
||||
const char** text,
|
||||
BerVarray *refs
|
||||
) */
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i=0; exop_table[i].extended != NULL; i++ ) {
|
||||
if( ber_bvcmp( exop_table[i].oid, &op->oq_extended.rs_reqoid ) == 0 ) {
|
||||
return (exop_table[i].extended)( op, rs );
|
||||
}
|
||||
}
|
||||
|
||||
rs->sr_text = "not supported within naming context";
|
||||
return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
||||
}
|
||||
|
||||
1144
servers/slapd/back-mdb/filterindex.c
Normal file
1144
servers/slapd/back-mdb/filterindex.c
Normal file
File diff suppressed because it is too large
Load diff
425
servers/slapd/back-mdb/id2entry.c
Normal file
425
servers/slapd/back-mdb/id2entry.c
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
/* id2entry.c - routines to deal with the id2entry database */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/errno.h>
|
||||
|
||||
#include "back-mdb.h"
|
||||
|
||||
static int mdb_id2entry_put(
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
Entry *e,
|
||||
int flag )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
|
||||
MDB_dbi dbi = mdb->mi_id2entry;
|
||||
MDB_val key, data;
|
||||
struct berval bv;
|
||||
int rc;
|
||||
struct berval odn, ondn;
|
||||
|
||||
/* We only store rdns, and they go in the dn2id database. */
|
||||
|
||||
odn = e->e_name; ondn = e->e_nname;
|
||||
|
||||
e->e_name = slap_empty_bv;
|
||||
e->e_nname = slap_empty_bv;
|
||||
|
||||
key.mv_data = &e->e_id;
|
||||
key.mv_size = sizeof(ID);
|
||||
|
||||
rc = entry_encode( e, &bv );
|
||||
e->e_name = odn; e->e_nname = ondn;
|
||||
if( rc != LDAP_SUCCESS ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data.mv_size = bv.bv_len;
|
||||
data.mv_data = bv.bv_val;
|
||||
|
||||
rc = mdb_put( tid, dbi, &key, &data, flag );
|
||||
|
||||
op->o_tmpfree( bv.bv_val, op->o_tmpmemctx );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine adds (or updates) an entry on disk.
|
||||
* The cache should be already be updated.
|
||||
*/
|
||||
|
||||
|
||||
int mdb_id2entry_add(
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
Entry *e )
|
||||
{
|
||||
return mdb_id2entry_put(op, tid, e, MDB_NOOVERWRITE);
|
||||
}
|
||||
|
||||
int mdb_id2entry_update(
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
Entry *e )
|
||||
{
|
||||
return mdb_id2entry_put(op, tid, e, 0);
|
||||
}
|
||||
|
||||
int mdb_id2entry(
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
ID id,
|
||||
Entry **e )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
|
||||
MDB_dbi dbi = mdb->mi_id2entry;
|
||||
MDB_val key, data;
|
||||
EntryHeader eh;
|
||||
int rc = 0;
|
||||
|
||||
*e = NULL;
|
||||
|
||||
key.mv_data = &id;
|
||||
key.mv_size = sizeof(ID);
|
||||
|
||||
/* fetch it */
|
||||
rc = mdb_get( tid, dbi, &key, &data );
|
||||
if ( rc == MDB_NOTFOUND ) {
|
||||
/* Looking for root entry on an empty-dn suffix? */
|
||||
if ( !id && BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] )) {
|
||||
struct berval gluebv = BER_BVC("glue");
|
||||
Entry *r = entry_alloc();
|
||||
|
||||
r->e_id = 0;
|
||||
attr_merge_one( r, slap_schema.si_ad_objectClass, &gluebv, NULL );
|
||||
attr_merge_one( r, slap_schema.si_ad_structuralObjectClass, &gluebv, NULL );
|
||||
r->e_ocflags = SLAP_OC_GLUE|SLAP_OC__END;
|
||||
*e = r;
|
||||
return MDB_SUCCESS;
|
||||
}
|
||||
}
|
||||
if ( rc ) return rc;
|
||||
|
||||
eh.bv.bv_val = data.mv_data;
|
||||
eh.bv.bv_len = data.mv_size;
|
||||
rc = entry_header( &eh );
|
||||
if ( rc ) return rc;
|
||||
|
||||
if ( eh.nvals ) {
|
||||
eh.bv.bv_len = eh.nvals * sizeof( struct berval );
|
||||
eh.bv.bv_val = ch_malloc( eh.bv.bv_len );
|
||||
rc = entry_decode(&eh, e);
|
||||
} else {
|
||||
*e = entry_alloc();
|
||||
}
|
||||
|
||||
if( rc == 0 ) {
|
||||
(*e)->e_id = id;
|
||||
(*e)->e_name.bv_val = NULL;
|
||||
(*e)->e_nname.bv_val = NULL;
|
||||
} else {
|
||||
ch_free( eh.bv.bv_val );
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int mdb_id2entry_delete(
|
||||
BackendDB *be,
|
||||
MDB_txn *tid,
|
||||
Entry *e )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
|
||||
MDB_dbi dbi = mdb->mi_id2entry;
|
||||
MDB_val key;
|
||||
int rc;
|
||||
|
||||
key.mv_data = &e->e_id;
|
||||
key.mv_size = sizeof(ID);
|
||||
|
||||
/* delete from database */
|
||||
rc = mdb_del( tid, dbi, &key, NULL );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int mdb_entry_return(
|
||||
Entry *e
|
||||
)
|
||||
{
|
||||
entry_free( e );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdb_entry_release(
|
||||
Operation *op,
|
||||
Entry *e,
|
||||
int rw )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
|
||||
struct mdb_op_info *moi = NULL;
|
||||
int rc;
|
||||
|
||||
/* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE,
|
||||
SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */
|
||||
|
||||
mdb_entry_return ( e );
|
||||
if ( slapMode == SLAP_SERVER_MODE ) {
|
||||
OpExtra *oex;
|
||||
LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
|
||||
if ( oex->oe_key == mdb ) {
|
||||
moi = (mdb_op_info *)oex;
|
||||
/* If it was setup by entry_get we should probably free it */
|
||||
if ( moi->moi_flag & MOI_FREEIT ) {
|
||||
moi->moi_ref--;
|
||||
if ( moi->moi_ref < 1 ) {
|
||||
mdb_txn_reset( moi->moi_txn );
|
||||
moi->moi_ref = 0;
|
||||
LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
|
||||
op->o_tmpfree( moi, op->o_tmpmemctx );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return LDAP_SUCCESS IFF we can retrieve the specified entry.
|
||||
*/
|
||||
int mdb_entry_get(
|
||||
Operation *op,
|
||||
struct berval *ndn,
|
||||
ObjectClass *oc,
|
||||
AttributeDescription *at,
|
||||
int rw,
|
||||
Entry **ent )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
|
||||
struct mdb_op_info *moi = NULL;
|
||||
MDB_txn *txn = NULL;
|
||||
Entry *e = NULL;
|
||||
int rc;
|
||||
const char *at_name = at ? at->ad_cname.bv_val : "(null)";
|
||||
|
||||
Debug( LDAP_DEBUG_ARGS,
|
||||
"=> mdb_entry_get: ndn: \"%s\"\n", ndn->bv_val, 0, 0 );
|
||||
Debug( LDAP_DEBUG_ARGS,
|
||||
"=> mdb_entry_get: oc: \"%s\", at: \"%s\"\n",
|
||||
oc ? oc->soc_cname.bv_val : "(null)", at_name, 0);
|
||||
|
||||
rc = mdb_opinfo_get( op, mdb, rw == 0, &moi );
|
||||
if ( rc )
|
||||
return LDAP_OTHER;
|
||||
txn = moi->moi_txn;
|
||||
|
||||
/* can we find entry */
|
||||
rc = mdb_dn2entry( op, txn, ndn, &e, 0 );
|
||||
switch( rc ) {
|
||||
case MDB_NOTFOUND:
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return (rc != LDAP_BUSY) ? LDAP_OTHER : LDAP_BUSY;
|
||||
}
|
||||
if (e == NULL) {
|
||||
Debug( LDAP_DEBUG_ACL,
|
||||
"=> mdb_entry_get: cannot find entry: \"%s\"\n",
|
||||
ndn->bv_val, 0, 0 );
|
||||
rc = LDAP_NO_SUCH_OBJECT;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_ACL,
|
||||
"=> mdb_entry_get: found entry: \"%s\"\n",
|
||||
ndn->bv_val, 0, 0 );
|
||||
|
||||
if ( oc && !is_entry_objectclass( e, oc, 0 )) {
|
||||
Debug( LDAP_DEBUG_ACL,
|
||||
"<= mdb_entry_get: failed to find objectClass %s\n",
|
||||
oc->soc_cname.bv_val, 0, 0 );
|
||||
rc = LDAP_NO_SUCH_ATTRIBUTE;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* NOTE: attr_find() or attrs_find()? */
|
||||
if ( at && attr_find( e->e_attrs, at ) == NULL ) {
|
||||
Debug( LDAP_DEBUG_ACL,
|
||||
"<= mdb_entry_get: failed to find attribute %s\n",
|
||||
at->ad_cname.bv_val, 0, 0 );
|
||||
rc = LDAP_NO_SUCH_ATTRIBUTE;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
return_results:
|
||||
if( rc != LDAP_SUCCESS ) {
|
||||
/* free entry */
|
||||
if ( e )
|
||||
mdb_entry_return( e );
|
||||
|
||||
if (moi->moi_ref == 1) {
|
||||
LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
|
||||
mdb_txn_reset( txn );
|
||||
op->o_tmpfree( moi, op->o_tmpmemctx );
|
||||
}
|
||||
} else {
|
||||
*ent = e;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"mdb_entry_get: rc=%d\n",
|
||||
rc, 0, 0 );
|
||||
return(rc);
|
||||
}
|
||||
|
||||
static void
|
||||
mdb_reader_free( void *key, void *data )
|
||||
{
|
||||
MDB_txn *txn = data;
|
||||
|
||||
if ( txn ) mdb_txn_abort( txn );
|
||||
}
|
||||
|
||||
/* free up any keys used by the main thread */
|
||||
void
|
||||
mdb_reader_flush( MDB_env *env )
|
||||
{
|
||||
void *data;
|
||||
void *ctx = ldap_pvt_thread_pool_context();
|
||||
|
||||
if ( !ldap_pvt_thread_pool_getkey( ctx, env, &data, NULL ) ) {
|
||||
ldap_pvt_thread_pool_setkey( ctx, env, NULL, 0, NULL, NULL );
|
||||
mdb_reader_free( env, data );
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
mdb_opinfo_get( Operation *op, struct mdb_info *mdb, int rdonly, mdb_op_info **moip )
|
||||
{
|
||||
int rc, renew = 0;
|
||||
void *data;
|
||||
void *ctx;
|
||||
mdb_op_info *moi = NULL;
|
||||
OpExtra *oex;
|
||||
|
||||
assert( op != NULL );
|
||||
|
||||
if ( !mdb || !moip ) return -1;
|
||||
|
||||
/* If no op was provided, try to find the ctx anyway... */
|
||||
if ( op ) {
|
||||
ctx = op->o_threadctx;
|
||||
} else {
|
||||
ctx = ldap_pvt_thread_pool_context();
|
||||
}
|
||||
|
||||
if ( op ) {
|
||||
LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
|
||||
if ( oex->oe_key == mdb ) break;
|
||||
}
|
||||
moi = (mdb_op_info *)oex;
|
||||
}
|
||||
|
||||
if ( !moi ) {
|
||||
moi = *moip;
|
||||
|
||||
if ( !moi ) {
|
||||
if ( op ) {
|
||||
moi = op->o_tmpalloc(sizeof(struct mdb_op_info),op->o_tmpmemctx);
|
||||
} else {
|
||||
moi = ch_malloc(sizeof(mdb_op_info));
|
||||
}
|
||||
moi->moi_flag = MOI_FREEIT;
|
||||
*moip = moi;
|
||||
}
|
||||
LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next );
|
||||
moi->moi_oe.oe_key = mdb;
|
||||
moi->moi_ref = 0;
|
||||
moi->moi_txn = NULL;
|
||||
}
|
||||
|
||||
if ( !rdonly ) {
|
||||
/* This op started as a reader, but now wants to write. */
|
||||
if ( moi->moi_flag & MOI_READER ) {
|
||||
moi = *moip;
|
||||
LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next );
|
||||
} else {
|
||||
/* This op is continuing an existing write txn */
|
||||
*moip = moi;
|
||||
}
|
||||
moi->moi_ref++;
|
||||
if ( !moi->moi_txn ) {
|
||||
rc = mdb_txn_begin( mdb->mi_dbenv, 0, &moi->moi_txn );
|
||||
if (rc) {
|
||||
Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
|
||||
mdb_strerror(rc), rc, 0 );
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* OK, this is a reader */
|
||||
if ( !moi->moi_txn ) {
|
||||
if ( !ctx ) {
|
||||
/* Shouldn't happen unless we're single-threaded */
|
||||
rc = mdb_txn_begin( mdb->mi_dbenv, MDB_RDONLY, &moi->moi_txn );
|
||||
if (rc) {
|
||||
Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
|
||||
mdb_strerror(rc), rc, 0 );
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
if ( ldap_pvt_thread_pool_getkey( ctx, mdb->mi_dbenv, &data, NULL ) ) {
|
||||
rc = mdb_txn_begin( mdb->mi_dbenv, MDB_RDONLY, &moi->moi_txn );
|
||||
if (rc) {
|
||||
Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
|
||||
mdb_strerror(rc), rc, 0 );
|
||||
return rc;
|
||||
}
|
||||
data = moi->moi_txn;
|
||||
if ( ( rc = ldap_pvt_thread_pool_setkey( ctx, mdb->mi_dbenv,
|
||||
data, mdb_reader_free, NULL, NULL ) ) ) {
|
||||
mdb_txn_abort( moi->moi_txn );
|
||||
moi->moi_txn = NULL;
|
||||
Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: thread_pool_setkey failed err (%d)\n",
|
||||
rc, 0, 0 );
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
moi->moi_txn = data;
|
||||
renew = 1;
|
||||
}
|
||||
moi->moi_flag |= MOI_READER;
|
||||
}
|
||||
if ( moi->moi_ref < 1 ) {
|
||||
moi->moi_ref = 0;
|
||||
}
|
||||
if ( renew ) {
|
||||
mdb_txn_renew( moi->moi_txn );
|
||||
}
|
||||
moi->moi_ref++;
|
||||
if ( *moip != moi )
|
||||
*moip = moi;
|
||||
|
||||
return 0;
|
||||
}
|
||||
1166
servers/slapd/back-mdb/idl.c
Normal file
1166
servers/slapd/back-mdb/idl.c
Normal file
File diff suppressed because it is too large
Load diff
74
servers/slapd/back-mdb/idl.h
Normal file
74
servers/slapd/back-mdb/idl.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/* idl.h - ldap mdb back-end ID list header file */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#ifndef _MDB_IDL_H_
|
||||
#define _MDB_IDL_H_
|
||||
|
||||
/* IDL sizes - likely should be even bigger
|
||||
* limiting factors: sizeof(ID), thread stack size
|
||||
*/
|
||||
#define MDB_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */
|
||||
#define MDB_IDL_DB_SIZE (1<<MDB_IDL_LOGN)
|
||||
#define MDB_IDL_UM_SIZE (1<<(MDB_IDL_LOGN+1))
|
||||
#define MDB_IDL_UM_SIZEOF (MDB_IDL_UM_SIZE * sizeof(ID))
|
||||
|
||||
#define MDB_IDL_DB_MAX (MDB_IDL_DB_SIZE-1)
|
||||
|
||||
#define MDB_IDL_UM_MAX (MDB_IDL_UM_SIZE-1)
|
||||
|
||||
#define MDB_IDL_IS_RANGE(ids) ((ids)[0] == NOID)
|
||||
#define MDB_IDL_RANGE_SIZE (3)
|
||||
#define MDB_IDL_RANGE_SIZEOF (MDB_IDL_RANGE_SIZE * sizeof(ID))
|
||||
#define MDB_IDL_SIZEOF(ids) ((MDB_IDL_IS_RANGE(ids) \
|
||||
? MDB_IDL_RANGE_SIZE : ((ids)[0]+1)) * sizeof(ID))
|
||||
|
||||
#define MDB_IDL_RANGE_FIRST(ids) ((ids)[1])
|
||||
#define MDB_IDL_RANGE_LAST(ids) ((ids)[2])
|
||||
|
||||
#define MDB_IDL_RANGE( ids, f, l ) \
|
||||
do { \
|
||||
(ids)[0] = NOID; \
|
||||
(ids)[1] = (f); \
|
||||
(ids)[2] = (l); \
|
||||
} while(0)
|
||||
|
||||
#define MDB_IDL_ZERO(ids) \
|
||||
do { \
|
||||
(ids)[0] = 0; \
|
||||
(ids)[1] = 0; \
|
||||
(ids)[2] = 0; \
|
||||
} while(0)
|
||||
|
||||
#define MDB_IDL_IS_ZERO(ids) ( (ids)[0] == 0 )
|
||||
#define MDB_IDL_IS_ALL( range, ids ) ( (ids)[0] == NOID \
|
||||
&& (ids)[1] <= (range)[1] && (range)[2] <= (ids)[2] )
|
||||
|
||||
#define MDB_IDL_CPY( dst, src ) (AC_MEMCPY( dst, src, MDB_IDL_SIZEOF( src ) ))
|
||||
|
||||
#define MDB_IDL_ID( mdb, ids, id ) MDB_IDL_RANGE( ids, id, NOID )
|
||||
#define MDB_IDL_ALL( ids ) MDB_IDL_RANGE( ids, 1, NOID )
|
||||
|
||||
#define MDB_IDL_FIRST( ids ) ( ids[1] )
|
||||
#define MDB_IDL_LAST( ids ) ( MDB_IDL_IS_RANGE(ids) \
|
||||
? ids[2] : ids[ids[0]] )
|
||||
|
||||
#define MDB_IDL_N( ids ) ( MDB_IDL_IS_RANGE(ids) \
|
||||
? (ids[2]-ids[1])+1 : ids[0] )
|
||||
|
||||
LDAP_BEGIN_DECL
|
||||
LDAP_END_DECL
|
||||
|
||||
#endif
|
||||
555
servers/slapd/back-mdb/index.c
Normal file
555
servers/slapd/back-mdb/index.c
Normal file
|
|
@ -0,0 +1,555 @@
|
|||
/* index.c - routines for dealing with attribute indexes */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/string.h>
|
||||
#include <ac/socket.h>
|
||||
|
||||
#include "slap.h"
|
||||
#include "back-mdb.h"
|
||||
#include "lutil_hash.h"
|
||||
|
||||
static char presence_keyval[] = {0,0};
|
||||
static struct berval presence_key = BER_BVC(presence_keyval);
|
||||
|
||||
AttrInfo *mdb_index_mask(
|
||||
Backend *be,
|
||||
AttributeDescription *desc,
|
||||
struct berval *atname )
|
||||
{
|
||||
AttributeType *at;
|
||||
AttrInfo *ai = mdb_attr_mask( be->be_private, desc );
|
||||
|
||||
if( ai ) {
|
||||
*atname = desc->ad_cname;
|
||||
return ai;
|
||||
}
|
||||
|
||||
/* If there is a tagging option, did we ever index the base
|
||||
* type? If so, check for mask, otherwise it's not there.
|
||||
*/
|
||||
if( slap_ad_is_tagged( desc ) && desc != desc->ad_type->sat_ad ) {
|
||||
/* has tagging option */
|
||||
ai = mdb_attr_mask( be->be_private, desc->ad_type->sat_ad );
|
||||
|
||||
if ( ai && !( ai->ai_indexmask & SLAP_INDEX_NOTAGS ) ) {
|
||||
*atname = desc->ad_type->sat_cname;
|
||||
return ai;
|
||||
}
|
||||
}
|
||||
|
||||
/* see if supertype defined mask for its subtypes */
|
||||
for( at = desc->ad_type; at != NULL ; at = at->sat_sup ) {
|
||||
/* If no AD, we've never indexed this type */
|
||||
if ( !at->sat_ad ) continue;
|
||||
|
||||
ai = mdb_attr_mask( be->be_private, at->sat_ad );
|
||||
|
||||
if ( ai && !( ai->ai_indexmask & SLAP_INDEX_NOSUBTYPES ) ) {
|
||||
*atname = at->sat_cname;
|
||||
return ai;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function is only called when evaluating search filters.
|
||||
*/
|
||||
int mdb_index_param(
|
||||
Backend *be,
|
||||
AttributeDescription *desc,
|
||||
int ftype,
|
||||
MDB_dbi *dbip,
|
||||
slap_mask_t *maskp,
|
||||
struct berval *prefixp )
|
||||
{
|
||||
AttrInfo *ai;
|
||||
slap_mask_t mask, type = 0;
|
||||
|
||||
ai = mdb_index_mask( be, desc, prefixp );
|
||||
|
||||
if ( !ai ) {
|
||||
#ifdef MDB_MONITOR_IDX
|
||||
switch ( ftype ) {
|
||||
case LDAP_FILTER_PRESENT:
|
||||
type = SLAP_INDEX_PRESENT;
|
||||
break;
|
||||
case LDAP_FILTER_APPROX:
|
||||
type = SLAP_INDEX_APPROX;
|
||||
break;
|
||||
case LDAP_FILTER_EQUALITY:
|
||||
type = SLAP_INDEX_EQUALITY;
|
||||
break;
|
||||
case LDAP_FILTER_SUBSTRINGS:
|
||||
type = SLAP_INDEX_SUBSTR;
|
||||
break;
|
||||
default:
|
||||
return LDAP_INAPPROPRIATE_MATCHING;
|
||||
}
|
||||
mdb_monitor_idx_add( be->be_private, desc, type );
|
||||
#endif /* MDB_MONITOR_IDX */
|
||||
|
||||
return LDAP_INAPPROPRIATE_MATCHING;
|
||||
}
|
||||
mask = ai->ai_indexmask;
|
||||
|
||||
switch( ftype ) {
|
||||
case LDAP_FILTER_PRESENT:
|
||||
type = SLAP_INDEX_PRESENT;
|
||||
if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
|
||||
*prefixp = presence_key;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
|
||||
case LDAP_FILTER_APPROX:
|
||||
type = SLAP_INDEX_APPROX;
|
||||
if ( desc->ad_type->sat_approx ) {
|
||||
if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Use EQUALITY rule and index for approximate match */
|
||||
/* fall thru */
|
||||
|
||||
case LDAP_FILTER_EQUALITY:
|
||||
type = SLAP_INDEX_EQUALITY;
|
||||
if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
|
||||
case LDAP_FILTER_SUBSTRINGS:
|
||||
type = SLAP_INDEX_SUBSTR;
|
||||
if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return LDAP_OTHER;
|
||||
}
|
||||
|
||||
#ifdef MDB_MONITOR_IDX
|
||||
mdb_monitor_idx_add( be->be_private, desc, type );
|
||||
#endif /* MDB_MONITOR_IDX */
|
||||
|
||||
return LDAP_INAPPROPRIATE_MATCHING;
|
||||
|
||||
done:
|
||||
*dbip = ai->ai_dbi;
|
||||
*maskp = mask;
|
||||
return LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
static int indexer(
|
||||
Operation *op,
|
||||
MDB_txn *txn,
|
||||
MDB_dbi dbi,
|
||||
AttributeDescription *ad,
|
||||
struct berval *atname,
|
||||
BerVarray vals,
|
||||
ID id,
|
||||
int opid,
|
||||
slap_mask_t mask )
|
||||
{
|
||||
int rc, i;
|
||||
struct berval *keys;
|
||||
|
||||
assert( mask != 0 );
|
||||
|
||||
if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
|
||||
rc = mdb_key_change( op->o_bd, txn, dbi, &presence_key, id, opid );
|
||||
if( rc ) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
|
||||
rc = ad->ad_type->sat_equality->smr_indexer(
|
||||
LDAP_FILTER_EQUALITY,
|
||||
mask,
|
||||
ad->ad_type->sat_syntax,
|
||||
ad->ad_type->sat_equality,
|
||||
atname, vals, &keys, op->o_tmpmemctx );
|
||||
|
||||
if( rc == LDAP_SUCCESS && keys != NULL ) {
|
||||
for( i=0; keys[i].bv_val != NULL; i++ ) {
|
||||
rc = mdb_key_change( op->o_bd, txn, dbi, &keys[i], id, opid );
|
||||
if( rc ) {
|
||||
ber_bvarray_free_x( keys, op->o_tmpmemctx );
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
ber_bvarray_free_x( keys, op->o_tmpmemctx );
|
||||
}
|
||||
rc = LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
|
||||
rc = ad->ad_type->sat_approx->smr_indexer(
|
||||
LDAP_FILTER_APPROX,
|
||||
mask,
|
||||
ad->ad_type->sat_syntax,
|
||||
ad->ad_type->sat_approx,
|
||||
atname, vals, &keys, op->o_tmpmemctx );
|
||||
|
||||
if( rc == LDAP_SUCCESS && keys != NULL ) {
|
||||
for( i=0; keys[i].bv_val != NULL; i++ ) {
|
||||
rc = mdb_key_change( op->o_bd, txn, dbi, &keys[i], id, opid );
|
||||
if( rc ) {
|
||||
ber_bvarray_free_x( keys, op->o_tmpmemctx );
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
ber_bvarray_free_x( keys, op->o_tmpmemctx );
|
||||
}
|
||||
|
||||
rc = LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
|
||||
rc = ad->ad_type->sat_substr->smr_indexer(
|
||||
LDAP_FILTER_SUBSTRINGS,
|
||||
mask,
|
||||
ad->ad_type->sat_syntax,
|
||||
ad->ad_type->sat_substr,
|
||||
atname, vals, &keys, op->o_tmpmemctx );
|
||||
|
||||
if( rc == LDAP_SUCCESS && keys != NULL ) {
|
||||
for( i=0; keys[i].bv_val != NULL; i++ ) {
|
||||
rc = mdb_key_change( op->o_bd, txn, dbi, &keys[i], id, opid );
|
||||
if( rc ) {
|
||||
ber_bvarray_free_x( keys, op->o_tmpmemctx );
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
ber_bvarray_free_x( keys, op->o_tmpmemctx );
|
||||
}
|
||||
|
||||
rc = LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
done:
|
||||
switch( rc ) {
|
||||
/* The callers all know how to deal with these results */
|
||||
case 0:
|
||||
break;
|
||||
/* Anything else is bad news */
|
||||
default:
|
||||
rc = LDAP_OTHER;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int index_at_values(
|
||||
Operation *op,
|
||||
MDB_txn *txn,
|
||||
AttributeDescription *ad,
|
||||
AttributeType *type,
|
||||
struct berval *tags,
|
||||
BerVarray vals,
|
||||
ID id,
|
||||
int opid )
|
||||
{
|
||||
int rc;
|
||||
slap_mask_t mask = 0;
|
||||
int ixop = opid;
|
||||
AttrInfo *ai = NULL;
|
||||
|
||||
if ( opid == MDB_INDEX_UPDATE_OP )
|
||||
ixop = SLAP_INDEX_ADD_OP;
|
||||
|
||||
if( type->sat_sup ) {
|
||||
/* recurse */
|
||||
rc = index_at_values( op, txn, NULL,
|
||||
type->sat_sup, tags,
|
||||
vals, id, opid );
|
||||
|
||||
if( rc ) return rc;
|
||||
}
|
||||
|
||||
/* If this type has no AD, we've never used it before */
|
||||
if( type->sat_ad ) {
|
||||
ai = mdb_attr_mask( op->o_bd->be_private, type->sat_ad );
|
||||
if ( ai ) {
|
||||
#ifdef LDAP_COMP_MATCH
|
||||
/* component indexing */
|
||||
if ( ai->ai_cr ) {
|
||||
ComponentReference *cr;
|
||||
for( cr = ai->ai_cr ; cr ; cr = cr->cr_next ) {
|
||||
rc = indexer( op, txn, ai->ai_dbi, cr->cr_ad, &type->sat_cname,
|
||||
cr->cr_nvals, id, ixop,
|
||||
cr->cr_indexmask );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ad = type->sat_ad;
|
||||
/* If we're updating the index, just set the new bits that aren't
|
||||
* already in the old mask.
|
||||
*/
|
||||
if ( opid == MDB_INDEX_UPDATE_OP )
|
||||
mask = ai->ai_newmask & ~ai->ai_indexmask;
|
||||
else
|
||||
/* For regular updates, if there is a newmask use it. Otherwise
|
||||
* just use the old mask.
|
||||
*/
|
||||
mask = ai->ai_newmask ? ai->ai_newmask : ai->ai_indexmask;
|
||||
if( mask ) {
|
||||
rc = indexer( op, txn, ai->ai_dbi, ad, &type->sat_cname,
|
||||
vals, id, ixop, mask );
|
||||
|
||||
if( rc ) return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( tags->bv_len ) {
|
||||
AttributeDescription *desc;
|
||||
|
||||
desc = ad_find_tags( type, tags );
|
||||
if( desc ) {
|
||||
ai = mdb_attr_mask( op->o_bd->be_private, desc );
|
||||
|
||||
if( ai ) {
|
||||
if ( opid == MDB_INDEX_UPDATE_OP )
|
||||
mask = ai->ai_newmask & ~ai->ai_indexmask;
|
||||
else
|
||||
mask = ai->ai_newmask ? ai->ai_newmask : ai->ai_indexmask;
|
||||
if ( mask ) {
|
||||
rc = indexer( op, txn, ai->ai_dbi, desc, &desc->ad_cname,
|
||||
vals, id, ixop, mask );
|
||||
|
||||
if( rc ) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
int mdb_index_values(
|
||||
Operation *op,
|
||||
MDB_txn *txn,
|
||||
AttributeDescription *desc,
|
||||
BerVarray vals,
|
||||
ID id,
|
||||
int opid )
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Never index ID 0 */
|
||||
if ( id == 0 )
|
||||
return 0;
|
||||
|
||||
rc = index_at_values( op, txn, desc,
|
||||
desc->ad_type, &desc->ad_tags,
|
||||
vals, id, opid );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Get the list of which indices apply to this attr */
|
||||
int
|
||||
mdb_index_recset(
|
||||
struct mdb_info *mdb,
|
||||
Attribute *a,
|
||||
AttributeType *type,
|
||||
struct berval *tags,
|
||||
IndexRec *ir )
|
||||
{
|
||||
int rc, slot;
|
||||
AttrList *al;
|
||||
|
||||
if( type->sat_sup ) {
|
||||
/* recurse */
|
||||
rc = mdb_index_recset( mdb, a, type->sat_sup, tags, ir );
|
||||
if( rc ) return rc;
|
||||
}
|
||||
/* If this type has no AD, we've never used it before */
|
||||
if( type->sat_ad ) {
|
||||
slot = mdb_attr_slot( mdb, type->sat_ad, NULL );
|
||||
if ( slot >= 0 ) {
|
||||
ir[slot].ai = mdb->mi_attrs[slot];
|
||||
al = ch_malloc( sizeof( AttrList ));
|
||||
al->attr = a;
|
||||
al->next = ir[slot].attrs;
|
||||
ir[slot].attrs = al;
|
||||
}
|
||||
}
|
||||
if( tags->bv_len ) {
|
||||
AttributeDescription *desc;
|
||||
|
||||
desc = ad_find_tags( type, tags );
|
||||
if( desc ) {
|
||||
slot = mdb_attr_slot( mdb, desc, NULL );
|
||||
if ( slot >= 0 ) {
|
||||
ir[slot].ai = mdb->mi_attrs[slot];
|
||||
al = ch_malloc( sizeof( AttrList ));
|
||||
al->attr = a;
|
||||
al->next = ir[slot].attrs;
|
||||
ir[slot].attrs = al;
|
||||
}
|
||||
}
|
||||
}
|
||||
return LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
/* Apply the indices for the recset */
|
||||
int mdb_index_recrun(
|
||||
Operation *op,
|
||||
struct mdb_info *mdb,
|
||||
IndexRec *ir0,
|
||||
ID id,
|
||||
int base )
|
||||
{
|
||||
IndexRec *ir;
|
||||
AttrList *al;
|
||||
int i, rc = 0;
|
||||
|
||||
/* Never index ID 0 */
|
||||
if ( id == 0 )
|
||||
return 0;
|
||||
|
||||
for (i=base; i<mdb->mi_nattrs; i+=slap_tool_thread_max) {
|
||||
ir = ir0 + i;
|
||||
if ( !ir->ai ) continue;
|
||||
while (( al = ir->attrs )) {
|
||||
ir->attrs = al->next;
|
||||
rc = indexer( op, NULL, ir->ai->ai_dbi, ir->ai->ai_desc,
|
||||
&ir->ai->ai_desc->ad_type->sat_cname,
|
||||
al->attr->a_nvals, id, SLAP_INDEX_ADD_OP,
|
||||
ir->ai->ai_indexmask );
|
||||
free( al );
|
||||
if ( rc ) break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
mdb_index_entry(
|
||||
Operation *op,
|
||||
MDB_txn *txn,
|
||||
int opid,
|
||||
Entry *e )
|
||||
{
|
||||
int rc;
|
||||
Attribute *ap = e->e_attrs;
|
||||
#if 0 /* ifdef LDAP_COMP_MATCH */
|
||||
ComponentReference *cr_list = NULL;
|
||||
ComponentReference *cr = NULL, *dupped_cr = NULL;
|
||||
void* decoded_comp;
|
||||
ComponentSyntaxInfo* csi_attr;
|
||||
Syntax* syn;
|
||||
AttributeType* at;
|
||||
int i, num_attr;
|
||||
void* mem_op;
|
||||
struct berval value = {0};
|
||||
#endif
|
||||
|
||||
/* Never index ID 0 */
|
||||
if ( e->e_id == 0 )
|
||||
return 0;
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "=> index_entry_%s( %ld, \"%s\" )\n",
|
||||
opid == SLAP_INDEX_DELETE_OP ? "del" : "add",
|
||||
(long) e->e_id, e->e_dn );
|
||||
|
||||
/* add each attribute to the indexes */
|
||||
for ( ; ap != NULL; ap = ap->a_next ) {
|
||||
#if 0 /* ifdef LDAP_COMP_MATCH */
|
||||
AttrInfo *ai;
|
||||
/* see if attribute has components to be indexed */
|
||||
ai = mdb_attr_mask( op->o_bd->be_private, ap->a_desc->ad_type->sat_ad );
|
||||
if ( !ai ) continue;
|
||||
cr_list = ai->ai_cr;
|
||||
if ( attr_converter && cr_list ) {
|
||||
syn = ap->a_desc->ad_type->sat_syntax;
|
||||
ap->a_comp_data = op->o_tmpalloc( sizeof( ComponentData ), op->o_tmpmemctx );
|
||||
/* Memory chunk(nibble) pre-allocation for decoders */
|
||||
mem_op = nibble_mem_allocator ( 1024*16, 1024*4 );
|
||||
ap->a_comp_data->cd_mem_op = mem_op;
|
||||
for( cr = cr_list ; cr ; cr = cr->cr_next ) {
|
||||
/* count how many values in an attribute */
|
||||
for( num_attr=0; ap->a_vals[num_attr].bv_val != NULL; num_attr++ );
|
||||
num_attr++;
|
||||
cr->cr_nvals = (BerVarray)op->o_tmpalloc( sizeof( struct berval )*num_attr, op->o_tmpmemctx );
|
||||
for( i=0; ap->a_vals[i].bv_val != NULL; i++ ) {
|
||||
/* decoding attribute value */
|
||||
decoded_comp = attr_converter ( ap, syn, &ap->a_vals[i] );
|
||||
if ( !decoded_comp )
|
||||
return LDAP_DECODING_ERROR;
|
||||
/* extracting the referenced component */
|
||||
dupped_cr = dup_comp_ref( op, cr );
|
||||
csi_attr = ((ComponentSyntaxInfo*)decoded_comp)->csi_comp_desc->cd_extract_i( mem_op, dupped_cr, decoded_comp );
|
||||
if ( !csi_attr )
|
||||
return LDAP_DECODING_ERROR;
|
||||
cr->cr_asn_type_id = csi_attr->csi_comp_desc->cd_type_id;
|
||||
cr->cr_ad = (AttributeDescription*)get_component_description ( cr->cr_asn_type_id );
|
||||
if ( !cr->cr_ad )
|
||||
return LDAP_INVALID_SYNTAX;
|
||||
at = cr->cr_ad->ad_type;
|
||||
/* encoding the value of component in GSER */
|
||||
rc = component_encoder( mem_op, csi_attr, &value );
|
||||
if ( rc != LDAP_SUCCESS )
|
||||
return LDAP_ENCODING_ERROR;
|
||||
/* Normalize the encoded component values */
|
||||
if ( at->sat_equality && at->sat_equality->smr_normalize ) {
|
||||
rc = at->sat_equality->smr_normalize (
|
||||
SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
|
||||
at->sat_syntax, at->sat_equality,
|
||||
&value, &cr->cr_nvals[i], op->o_tmpmemctx );
|
||||
} else {
|
||||
cr->cr_nvals[i] = value;
|
||||
}
|
||||
}
|
||||
/* The end of BerVarray */
|
||||
cr->cr_nvals[num_attr-1].bv_val = NULL;
|
||||
cr->cr_nvals[num_attr-1].bv_len = 0;
|
||||
}
|
||||
op->o_tmpfree( ap->a_comp_data, op->o_tmpmemctx );
|
||||
nibble_mem_free ( mem_op );
|
||||
ap->a_comp_data = NULL;
|
||||
}
|
||||
#endif
|
||||
rc = mdb_index_values( op, txn, ap->a_desc,
|
||||
ap->a_nvals, e->e_id, opid );
|
||||
|
||||
if( rc != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"<= index_entry_%s( %ld, \"%s\" ) failure\n",
|
||||
opid == SLAP_INDEX_ADD_OP ? "add" : "del",
|
||||
(long) e->e_id, e->e_dn );
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "<= index_entry_%s( %ld, \"%s\" ) success\n",
|
||||
opid == SLAP_INDEX_DELETE_OP ? "del" : "add",
|
||||
(long) e->e_id, e->e_dn );
|
||||
|
||||
return LDAP_SUCCESS;
|
||||
}
|
||||
445
servers/slapd/back-mdb/init.c
Normal file
445
servers/slapd/back-mdb/init.c
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
/* init.c - initialize mdb backend */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#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 "back-mdb.h"
|
||||
#include <lutil.h>
|
||||
#include <ldap_rq.h>
|
||||
#include "config.h"
|
||||
|
||||
static const struct berval mdmi_databases[] = {
|
||||
BER_BVC("ad2i"),
|
||||
BER_BVC("dn2i"),
|
||||
BER_BVC("id2e"),
|
||||
BER_BVNULL
|
||||
};
|
||||
|
||||
static int
|
||||
mdb_db_init( BackendDB *be, ConfigReply *cr )
|
||||
{
|
||||
struct mdb_info *mdb;
|
||||
int rc;
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_db_init) ": Initializing mdb database\n",
|
||||
0, 0, 0 );
|
||||
|
||||
/* allocate backend-database-specific stuff */
|
||||
mdb = (struct mdb_info *) ch_calloc( 1, sizeof(struct mdb_info) );
|
||||
|
||||
/* DBEnv parameters */
|
||||
mdb->mi_dbenv_home = ch_strdup( SLAPD_DEFAULT_DB_DIR );
|
||||
mdb->mi_dbenv_flags = 0;
|
||||
mdb->mi_dbenv_mode = SLAPD_DEFAULT_DB_MODE;
|
||||
|
||||
mdb->mi_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH;
|
||||
mdb->mi_search_stack = NULL;
|
||||
|
||||
mdb->mi_mapsize = DEFAULT_MAPSIZE;
|
||||
|
||||
be->be_private = mdb;
|
||||
be->be_cf_ocs = be->bd_info->bi_cf_ocs;
|
||||
|
||||
#ifndef MDB_MULTIPLE_SUFFIXES
|
||||
SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
|
||||
#endif
|
||||
|
||||
rc = mdb_monitor_db_init( be );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
mdb_db_close( BackendDB *be, ConfigReply *cr );
|
||||
|
||||
static int
|
||||
mdb_db_open( BackendDB *be, ConfigReply *cr )
|
||||
{
|
||||
int rc, i;
|
||||
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
|
||||
struct stat stat1;
|
||||
u_int32_t flags;
|
||||
char *dbhome;
|
||||
MDB_txn *txn;
|
||||
|
||||
if ( be->be_suffix == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_db_open) ": need suffix.\n",
|
||||
1, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_ARGS,
|
||||
LDAP_XSTRING(mdb_db_open) ": \"%s\"\n",
|
||||
be->be_suffix[0].bv_val, 0, 0 );
|
||||
|
||||
/* Check existence of dbenv_home. Any error means trouble */
|
||||
rc = stat( mdb->mi_dbenv_home, &stat1 );
|
||||
if( rc != 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
|
||||
"cannot access database directory \"%s\" (%d).\n",
|
||||
be->be_suffix[0].bv_val, mdb->mi_dbenv_home, errno );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* mdb is always clean */
|
||||
be->be_flags |= SLAP_DBFLAG_CLEAN;
|
||||
|
||||
rc = mdb_env_create( &mdb->mi_dbenv );
|
||||
if( rc != 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
|
||||
"mdb_env_create failed: %s (%d).\n",
|
||||
be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( mdb->mi_readers ) {
|
||||
rc = mdb_env_set_maxreaders( mdb->mi_dbenv, mdb->mi_readers );
|
||||
if( rc != 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
|
||||
"mdb_env_set_maxreaders failed: %s (%d).\n",
|
||||
be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
rc = mdb_env_set_mapsize( mdb->mi_dbenv, mdb->mi_mapsize );
|
||||
if( rc != 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
|
||||
"mdb_env_set_mapsize failed: %s (%d).\n",
|
||||
be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = mdb_env_set_maxdbs( mdb->mi_dbenv, MDB_INDICES );
|
||||
if( rc != 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
|
||||
"mdb_env_set_maxdbs failed: %s (%d).\n",
|
||||
be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef HAVE_EBCDIC
|
||||
strcpy( path, mdb->mi_dbenv_home );
|
||||
__atoe( path );
|
||||
dbhome = path;
|
||||
#else
|
||||
dbhome = mdb->mi_dbenv_home;
|
||||
#endif
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
|
||||
"dbenv_open(%s).\n",
|
||||
be->be_suffix[0].bv_val, mdb->mi_dbenv_home, 0);
|
||||
|
||||
flags = mdb->mi_dbenv_flags;
|
||||
|
||||
if ( slapMode & SLAP_TOOL_QUICK )
|
||||
flags |= MDB_NOSYNC;
|
||||
|
||||
if ( slapMode & SLAP_TOOL_READONLY)
|
||||
flags |= MDB_RDONLY;
|
||||
|
||||
rc = mdb_env_open( mdb->mi_dbenv, dbhome,
|
||||
flags, mdb->mi_dbenv_mode );
|
||||
|
||||
if ( rc ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_db_open) ": database \"%s\" cannot be opened, err %d. "
|
||||
"Restore from backup!\n",
|
||||
be->be_suffix[0].bv_val, rc, 0 );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = mdb_txn_begin( mdb->mi_dbenv, 0, &txn );
|
||||
if ( rc ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_db_open) ": database \"%s\" cannot be opened, err %d. "
|
||||
"Restore from backup!\n",
|
||||
be->be_suffix[0].bv_val, rc, 0 );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* open (and create) main databases */
|
||||
for( i = 0; mdmi_databases[i].bv_val; i++ ) {
|
||||
flags = MDB_INTEGERKEY;
|
||||
if( i == MDB_ID2ENTRY ) {
|
||||
if ( !(slapMode & (SLAP_TOOL_READMAIN|SLAP_TOOL_READONLY) ))
|
||||
flags |= MDB_CREATE;
|
||||
} else {
|
||||
if ( i == MDB_DN2ID )
|
||||
flags |= MDB_DUPSORT;
|
||||
if ( !(slapMode & SLAP_TOOL_READONLY) )
|
||||
flags |= MDB_CREATE;
|
||||
}
|
||||
|
||||
rc = mdb_open( txn,
|
||||
mdmi_databases[i].bv_val,
|
||||
flags,
|
||||
&mdb->mi_dbis[i] );
|
||||
|
||||
if ( rc != 0 ) {
|
||||
snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
|
||||
"mdb_open(%s/%s) failed: %s (%d).",
|
||||
be->be_suffix[0].bv_val,
|
||||
mdb->mi_dbenv_home, mdmi_databases[i].bv_val,
|
||||
mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_db_open) ": %s\n",
|
||||
cr->msg, 0, 0 );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( i == MDB_DN2ID )
|
||||
mdb_set_dupsort( txn, mdb->mi_dbis[i], mdb_dup_compare );
|
||||
|
||||
}
|
||||
|
||||
rc = mdb_attr_dbs_open( be, txn, cr );
|
||||
if ( rc ) {
|
||||
mdb_txn_abort( txn );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = mdb_txn_commit(txn);
|
||||
if ( rc != 0 ) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* monitor setup */
|
||||
rc = mdb_monitor_db_open( be );
|
||||
if ( rc != 0 ) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mdb->mi_flags |= MDB_IS_OPEN;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
mdb_db_close( be, NULL );
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
mdb_db_close( BackendDB *be, ConfigReply *cr )
|
||||
{
|
||||
int rc;
|
||||
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
|
||||
MDB_txn *txn;
|
||||
|
||||
/* monitor handling */
|
||||
(void)mdb_monitor_db_close( be );
|
||||
|
||||
mdb->mi_flags &= ~MDB_IS_OPEN;
|
||||
|
||||
if( mdb->mi_dbenv ) {
|
||||
mdb_reader_flush( mdb->mi_dbenv );
|
||||
}
|
||||
|
||||
if ( mdb->mi_dbenv ) {
|
||||
if ( mdb->mi_dbis[0] ) {
|
||||
int i;
|
||||
rc = mdb_txn_begin( mdb->mi_dbenv, MDB_RDONLY, &txn );
|
||||
|
||||
mdb_attr_dbs_close( mdb, txn );
|
||||
for ( i=0; i<MDB_NDB; i++ )
|
||||
mdb_close( txn, mdb->mi_dbis[i] );
|
||||
|
||||
mdb_txn_abort( txn );
|
||||
|
||||
/* force a sync */
|
||||
rc = mdb_env_sync( mdb->mi_dbenv, 1 );
|
||||
if( rc != 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"mdb_db_close: database \"%s\": "
|
||||
"mdb_env_sync failed: %s (%d).\n",
|
||||
be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
|
||||
}
|
||||
}
|
||||
|
||||
mdb_env_close( mdb->mi_dbenv );
|
||||
mdb->mi_dbenv = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mdb_db_destroy( BackendDB *be, ConfigReply *cr )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
|
||||
|
||||
/* stop and remove checkpoint task */
|
||||
if ( mdb->mi_txn_cp_task ) {
|
||||
struct re_s *re = mdb->mi_txn_cp_task;
|
||||
mdb->mi_txn_cp_task = NULL;
|
||||
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
|
||||
if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
|
||||
ldap_pvt_runqueue_stoptask( &slapd_rq, re );
|
||||
ldap_pvt_runqueue_remove( &slapd_rq, re );
|
||||
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
|
||||
}
|
||||
|
||||
/* monitor handling */
|
||||
(void)mdb_monitor_db_destroy( be );
|
||||
|
||||
if( mdb->mi_dbenv_home ) ch_free( mdb->mi_dbenv_home );
|
||||
|
||||
mdb_attr_index_destroy( mdb );
|
||||
|
||||
ch_free( mdb );
|
||||
be->be_private = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mdb_back_initialize(
|
||||
BackendInfo *bi )
|
||||
{
|
||||
int rc;
|
||||
|
||||
static char *controls[] = {
|
||||
LDAP_CONTROL_ASSERT,
|
||||
LDAP_CONTROL_MANAGEDSAIT,
|
||||
LDAP_CONTROL_NOOP,
|
||||
LDAP_CONTROL_PAGEDRESULTS,
|
||||
LDAP_CONTROL_PRE_READ,
|
||||
LDAP_CONTROL_POST_READ,
|
||||
LDAP_CONTROL_SUBENTRIES,
|
||||
LDAP_CONTROL_X_PERMISSIVE_MODIFY,
|
||||
#ifdef LDAP_X_TXN
|
||||
LDAP_CONTROL_X_TXN_SPEC,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
/* initialize the underlying database system */
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_back_initialize) ": initialize "
|
||||
MDB_UCTYPE " backend\n", 0, 0, 0 );
|
||||
|
||||
bi->bi_flags |=
|
||||
SLAP_BFLAG_INCREMENT |
|
||||
SLAP_BFLAG_SUBENTRIES |
|
||||
SLAP_BFLAG_ALIASES |
|
||||
SLAP_BFLAG_REFERRALS;
|
||||
|
||||
bi->bi_controls = controls;
|
||||
|
||||
{ /* version check */
|
||||
int major, minor, patch, ver;
|
||||
char *version = mdb_version( &major, &minor, &patch );
|
||||
#ifdef HAVE_EBCDIC
|
||||
char v2[1024];
|
||||
|
||||
/* All our stdio does an ASCII to EBCDIC conversion on
|
||||
* the output. Strings from the MDB library are already
|
||||
* in EBCDIC; we have to go back and forth...
|
||||
*/
|
||||
strcpy( v2, version );
|
||||
__etoa( v2 );
|
||||
version = v2;
|
||||
#endif
|
||||
ver = (major << 24) | (minor << 16) | patch;
|
||||
if( ver != MDB_VERSION_FULL ) {
|
||||
/* fail if a versions don't match */
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_back_initialize) ": "
|
||||
"MDB library version mismatch:"
|
||||
" expected " MDB_VERSION_STRING ","
|
||||
" got %s\n", version, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_back_initialize)
|
||||
": %s\n", version, 0, 0 );
|
||||
}
|
||||
|
||||
bi->bi_open = 0;
|
||||
bi->bi_close = 0;
|
||||
bi->bi_config = 0;
|
||||
bi->bi_destroy = 0;
|
||||
|
||||
bi->bi_db_init = mdb_db_init;
|
||||
bi->bi_db_config = config_generic_wrapper;
|
||||
bi->bi_db_open = mdb_db_open;
|
||||
bi->bi_db_close = mdb_db_close;
|
||||
bi->bi_db_destroy = mdb_db_destroy;
|
||||
|
||||
bi->bi_op_add = mdb_add;
|
||||
bi->bi_op_bind = mdb_bind;
|
||||
bi->bi_op_compare = mdb_compare;
|
||||
bi->bi_op_delete = mdb_delete;
|
||||
bi->bi_op_modify = mdb_modify;
|
||||
bi->bi_op_modrdn = mdb_modrdn;
|
||||
bi->bi_op_search = mdb_search;
|
||||
|
||||
bi->bi_op_unbind = 0;
|
||||
|
||||
bi->bi_extended = mdb_extended;
|
||||
|
||||
#if 0 /* FIXME: Redundant, why does this exist? */
|
||||
bi->bi_chk_referrals = mdb_referrals;
|
||||
#endif
|
||||
bi->bi_operational = mdb_operational;
|
||||
|
||||
bi->bi_has_subordinates = mdb_hasSubordinates;
|
||||
bi->bi_entry_release_rw = mdb_entry_release;
|
||||
bi->bi_entry_get_rw = mdb_entry_get;
|
||||
|
||||
/*
|
||||
* hooks for slap tools
|
||||
*/
|
||||
bi->bi_tool_entry_open = mdb_tool_entry_open;
|
||||
bi->bi_tool_entry_close = mdb_tool_entry_close;
|
||||
bi->bi_tool_entry_first = backend_tool_entry_first;
|
||||
bi->bi_tool_entry_first_x = mdb_tool_entry_first_x;
|
||||
bi->bi_tool_entry_next = mdb_tool_entry_next;
|
||||
bi->bi_tool_entry_get = mdb_tool_entry_get;
|
||||
bi->bi_tool_entry_put = mdb_tool_entry_put;
|
||||
bi->bi_tool_entry_reindex = mdb_tool_entry_reindex;
|
||||
bi->bi_tool_sync = 0;
|
||||
bi->bi_tool_dn2id_get = mdb_tool_dn2id_get;
|
||||
bi->bi_tool_entry_modify = mdb_tool_entry_modify;
|
||||
|
||||
bi->bi_connection_init = 0;
|
||||
bi->bi_connection_destroy = 0;
|
||||
|
||||
rc = mdb_back_init_cf( bi );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if (SLAPD_MDB == SLAPD_MOD_DYNAMIC)
|
||||
|
||||
SLAP_BACKEND_INIT_MODULE( mdb )
|
||||
|
||||
#endif /* SLAPD_MDB == SLAPD_MOD_DYNAMIC */
|
||||
|
||||
94
servers/slapd/back-mdb/key.c
Normal file
94
servers/slapd/back-mdb/key.c
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/* index.c - routines for dealing with attribute indexes */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/string.h>
|
||||
#include <ac/socket.h>
|
||||
|
||||
#include "slap.h"
|
||||
#include "back-mdb.h"
|
||||
#include "idl.h"
|
||||
|
||||
/* read a key */
|
||||
int
|
||||
mdb_key_read(
|
||||
Backend *be,
|
||||
MDB_txn *txn,
|
||||
MDB_dbi dbi,
|
||||
struct berval *k,
|
||||
ID *ids,
|
||||
MDB_cursor **saved_cursor,
|
||||
int get_flag
|
||||
)
|
||||
{
|
||||
int rc;
|
||||
MDB_val key;
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "=> key_read\n", 0, 0, 0 );
|
||||
|
||||
key.mv_size = k->bv_len;
|
||||
key.mv_data = k->bv_val;
|
||||
|
||||
rc = mdb_idl_fetch_key( be, txn, dbi, &key, ids, saved_cursor, get_flag );
|
||||
|
||||
if( rc != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "<= mdb_index_read: failed (%d)\n",
|
||||
rc, 0, 0 );
|
||||
} else {
|
||||
Debug( LDAP_DEBUG_TRACE, "<= mdb_index_read %ld candidates\n",
|
||||
(long) MDB_IDL_N(ids), 0, 0 );
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Add or remove stuff from index files */
|
||||
int
|
||||
mdb_key_change(
|
||||
Backend *be,
|
||||
MDB_txn *txn,
|
||||
MDB_dbi dbi,
|
||||
struct berval *k,
|
||||
ID id,
|
||||
int op
|
||||
)
|
||||
{
|
||||
int rc;
|
||||
MDB_val key;
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "=> key_change(%s,%lx)\n",
|
||||
op == SLAP_INDEX_ADD_OP ? "ADD":"DELETE", (long) id, 0 );
|
||||
|
||||
key.mv_size = k->bv_len;
|
||||
key.mv_data = k->bv_val;
|
||||
|
||||
if (op == SLAP_INDEX_ADD_OP) {
|
||||
/* Add values */
|
||||
rc = mdb_idl_insert_key( be, txn, dbi, &key, id );
|
||||
if ( rc == MDB_KEYEXIST ) rc = 0;
|
||||
} else {
|
||||
/* Delete values */
|
||||
rc = mdb_idl_delete_key( be, txn, dbi, &key, id );
|
||||
if ( rc == MDB_NOTFOUND ) rc = 0;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "<= key_change %d\n", rc, 0, 0 );
|
||||
|
||||
return rc;
|
||||
}
|
||||
693
servers/slapd/back-mdb/modify.c
Normal file
693
servers/slapd/back-mdb/modify.c
Normal file
|
|
@ -0,0 +1,693 @@
|
|||
/* modify.c - mdb backend modify routine */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/time.h>
|
||||
|
||||
#include "back-mdb.h"
|
||||
|
||||
static struct berval scbva[] = {
|
||||
BER_BVC("glue"),
|
||||
BER_BVNULL
|
||||
};
|
||||
|
||||
static void
|
||||
mdb_modify_idxflags(
|
||||
Operation *op,
|
||||
AttributeDescription *desc,
|
||||
int got_delete,
|
||||
Attribute *newattrs,
|
||||
Attribute *oldattrs )
|
||||
{
|
||||
struct berval ix_at;
|
||||
AttrInfo *ai;
|
||||
|
||||
/* check if modified attribute was indexed
|
||||
* but not in case of NOOP... */
|
||||
ai = mdb_index_mask( op->o_bd, desc, &ix_at );
|
||||
if ( ai ) {
|
||||
if ( got_delete ) {
|
||||
Attribute *ap;
|
||||
struct berval ix2;
|
||||
|
||||
ap = attr_find( oldattrs, desc );
|
||||
if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL;
|
||||
|
||||
/* Find all other attrs that index to same slot */
|
||||
for ( ap = newattrs; ap; ap = ap->a_next ) {
|
||||
ai = mdb_index_mask( op->o_bd, ap->a_desc, &ix2 );
|
||||
if ( ai && ix2.bv_val == ix_at.bv_val )
|
||||
ap->a_flags |= SLAP_ATTR_IXADD;
|
||||
}
|
||||
|
||||
} else {
|
||||
Attribute *ap;
|
||||
|
||||
ap = attr_find( newattrs, desc );
|
||||
if ( ap ) ap->a_flags |= SLAP_ATTR_IXADD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int mdb_modify_internal(
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
Modifications *modlist,
|
||||
Entry *e,
|
||||
const char **text,
|
||||
char *textbuf,
|
||||
size_t textlen )
|
||||
{
|
||||
int rc, err;
|
||||
Modification *mod;
|
||||
Modifications *ml;
|
||||
Attribute *save_attrs;
|
||||
Attribute *ap;
|
||||
int glue_attr_delete = 0;
|
||||
int got_delete;
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "mdb_modify_internal: 0x%08lx: %s\n",
|
||||
e->e_id, e->e_dn, 0);
|
||||
|
||||
if ( !acl_check_modlist( op, e, modlist )) {
|
||||
return LDAP_INSUFFICIENT_ACCESS;
|
||||
}
|
||||
|
||||
/* save_attrs will be disposed of by mdb_cache_modify */
|
||||
save_attrs = e->e_attrs;
|
||||
e->e_attrs = attrs_dup( e->e_attrs );
|
||||
|
||||
for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
|
||||
int match;
|
||||
mod = &ml->sml_mod;
|
||||
switch( mod->sm_op ) {
|
||||
case LDAP_MOD_ADD:
|
||||
case LDAP_MOD_REPLACE:
|
||||
if ( mod->sm_desc == slap_schema.si_ad_structuralObjectClass ) {
|
||||
value_match( &match, slap_schema.si_ad_structuralObjectClass,
|
||||
slap_schema.si_ad_structuralObjectClass->
|
||||
ad_type->sat_equality,
|
||||
SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
|
||||
&mod->sm_values[0], &scbva[0], text );
|
||||
if ( !match ) glue_attr_delete = 1;
|
||||
}
|
||||
}
|
||||
if ( glue_attr_delete )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( glue_attr_delete ) {
|
||||
Attribute **app = &e->e_attrs;
|
||||
while ( *app != NULL ) {
|
||||
if ( !is_at_operational( (*app)->a_desc->ad_type )) {
|
||||
Attribute *save = *app;
|
||||
*app = (*app)->a_next;
|
||||
attr_free( save );
|
||||
continue;
|
||||
}
|
||||
app = &(*app)->a_next;
|
||||
}
|
||||
}
|
||||
|
||||
for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
|
||||
mod = &ml->sml_mod;
|
||||
got_delete = 0;
|
||||
|
||||
switch ( mod->sm_op ) {
|
||||
case LDAP_MOD_ADD:
|
||||
Debug(LDAP_DEBUG_ARGS,
|
||||
"mdb_modify_internal: add %s\n",
|
||||
mod->sm_desc->ad_cname.bv_val, 0, 0);
|
||||
err = modify_add_values( e, mod, get_permissiveModify(op),
|
||||
text, textbuf, textlen );
|
||||
if( err != LDAP_SUCCESS ) {
|
||||
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
|
||||
err, *text, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case LDAP_MOD_DELETE:
|
||||
if ( glue_attr_delete ) {
|
||||
err = LDAP_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
Debug(LDAP_DEBUG_ARGS,
|
||||
"mdb_modify_internal: delete %s\n",
|
||||
mod->sm_desc->ad_cname.bv_val, 0, 0);
|
||||
err = modify_delete_values( e, mod, get_permissiveModify(op),
|
||||
text, textbuf, textlen );
|
||||
if( err != LDAP_SUCCESS ) {
|
||||
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
|
||||
err, *text, 0);
|
||||
} else {
|
||||
got_delete = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case LDAP_MOD_REPLACE:
|
||||
Debug(LDAP_DEBUG_ARGS,
|
||||
"mdb_modify_internal: replace %s\n",
|
||||
mod->sm_desc->ad_cname.bv_val, 0, 0);
|
||||
err = modify_replace_values( e, mod, get_permissiveModify(op),
|
||||
text, textbuf, textlen );
|
||||
if( err != LDAP_SUCCESS ) {
|
||||
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
|
||||
err, *text, 0);
|
||||
} else {
|
||||
got_delete = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case LDAP_MOD_INCREMENT:
|
||||
Debug(LDAP_DEBUG_ARGS,
|
||||
"mdb_modify_internal: increment %s\n",
|
||||
mod->sm_desc->ad_cname.bv_val, 0, 0);
|
||||
err = modify_increment_values( e, mod, get_permissiveModify(op),
|
||||
text, textbuf, textlen );
|
||||
if( err != LDAP_SUCCESS ) {
|
||||
Debug(LDAP_DEBUG_ARGS,
|
||||
"mdb_modify_internal: %d %s\n",
|
||||
err, *text, 0);
|
||||
} else {
|
||||
got_delete = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case SLAP_MOD_SOFTADD:
|
||||
Debug(LDAP_DEBUG_ARGS,
|
||||
"mdb_modify_internal: softadd %s\n",
|
||||
mod->sm_desc->ad_cname.bv_val, 0, 0);
|
||||
/* Avoid problems in index_add_mods()
|
||||
* We need to add index if necessary.
|
||||
*/
|
||||
mod->sm_op = LDAP_MOD_ADD;
|
||||
|
||||
err = modify_add_values( e, mod, get_permissiveModify(op),
|
||||
text, textbuf, textlen );
|
||||
|
||||
mod->sm_op = SLAP_MOD_SOFTADD;
|
||||
|
||||
if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) {
|
||||
err = LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
if( err != LDAP_SUCCESS ) {
|
||||
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
|
||||
err, *text, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case SLAP_MOD_SOFTDEL:
|
||||
Debug(LDAP_DEBUG_ARGS,
|
||||
"mdb_modify_internal: softdel %s\n",
|
||||
mod->sm_desc->ad_cname.bv_val, 0, 0);
|
||||
/* Avoid problems in index_delete_mods()
|
||||
* We need to add index if necessary.
|
||||
*/
|
||||
mod->sm_op = LDAP_MOD_DELETE;
|
||||
|
||||
err = modify_delete_values( e, mod, get_permissiveModify(op),
|
||||
text, textbuf, textlen );
|
||||
|
||||
mod->sm_op = SLAP_MOD_SOFTDEL;
|
||||
|
||||
if ( err == LDAP_NO_SUCH_ATTRIBUTE ) {
|
||||
err = LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
if( err != LDAP_SUCCESS ) {
|
||||
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
|
||||
err, *text, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case SLAP_MOD_ADD_IF_NOT_PRESENT:
|
||||
if ( attr_find( e->e_attrs, mod->sm_desc ) != NULL ) {
|
||||
/* skip */
|
||||
err = LDAP_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
Debug(LDAP_DEBUG_ARGS,
|
||||
"mdb_modify_internal: add_if_not_present %s\n",
|
||||
mod->sm_desc->ad_cname.bv_val, 0, 0);
|
||||
/* Avoid problems in index_add_mods()
|
||||
* We need to add index if necessary.
|
||||
*/
|
||||
mod->sm_op = LDAP_MOD_ADD;
|
||||
|
||||
err = modify_add_values( e, mod, get_permissiveModify(op),
|
||||
text, textbuf, textlen );
|
||||
|
||||
mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
|
||||
|
||||
if( err != LDAP_SUCCESS ) {
|
||||
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
|
||||
err, *text, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug(LDAP_DEBUG_ANY, "mdb_modify_internal: invalid op %d\n",
|
||||
mod->sm_op, 0, 0);
|
||||
*text = "Invalid modify operation";
|
||||
err = LDAP_OTHER;
|
||||
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
|
||||
err, *text, 0);
|
||||
}
|
||||
|
||||
if ( err != LDAP_SUCCESS ) {
|
||||
attrs_free( e->e_attrs );
|
||||
e->e_attrs = save_attrs;
|
||||
/* unlock entry, delete from cache */
|
||||
return err;
|
||||
}
|
||||
|
||||
/* If objectClass was modified, reset the flags */
|
||||
if ( mod->sm_desc == slap_schema.si_ad_objectClass ) {
|
||||
e->e_ocflags = 0;
|
||||
}
|
||||
|
||||
if ( glue_attr_delete ) e->e_ocflags = 0;
|
||||
|
||||
|
||||
/* check if modified attribute was indexed
|
||||
* but not in case of NOOP... */
|
||||
if ( !op->o_noop ) {
|
||||
mdb_modify_idxflags( op, mod->sm_desc, got_delete, e->e_attrs, save_attrs );
|
||||
}
|
||||
}
|
||||
|
||||
/* check that the entry still obeys the schema */
|
||||
ap = NULL;
|
||||
rc = entry_schema_check( op, e, save_attrs, get_relax(op), 0, &ap,
|
||||
text, textbuf, textlen );
|
||||
if ( rc != LDAP_SUCCESS || op->o_noop ) {
|
||||
attrs_free( e->e_attrs );
|
||||
/* clear the indexing flags */
|
||||
for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) {
|
||||
ap->a_flags &= ~(SLAP_ATTR_IXADD|SLAP_ATTR_IXDEL);
|
||||
}
|
||||
e->e_attrs = save_attrs;
|
||||
|
||||
if ( rc != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"entry failed schema check: %s\n",
|
||||
*text, 0, 0 );
|
||||
}
|
||||
|
||||
/* if NOOP then silently revert to saved attrs */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* structuralObjectClass modified! */
|
||||
if ( ap ) {
|
||||
assert( ap->a_desc == slap_schema.si_ad_structuralObjectClass );
|
||||
if ( !op->o_noop ) {
|
||||
mdb_modify_idxflags( op, slap_schema.si_ad_structuralObjectClass,
|
||||
1, e->e_attrs, save_attrs );
|
||||
}
|
||||
}
|
||||
|
||||
/* update the indices of the modified attributes */
|
||||
|
||||
/* start with deleting the old index entries */
|
||||
for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) {
|
||||
if ( ap->a_flags & SLAP_ATTR_IXDEL ) {
|
||||
struct berval *vals;
|
||||
Attribute *a2;
|
||||
ap->a_flags &= ~SLAP_ATTR_IXDEL;
|
||||
a2 = attr_find( e->e_attrs, ap->a_desc );
|
||||
if ( a2 ) {
|
||||
/* need to detect which values were deleted */
|
||||
int i, j;
|
||||
vals = op->o_tmpalloc( (ap->a_numvals + 1) *
|
||||
sizeof(struct berval), op->o_tmpmemctx );
|
||||
j = 0;
|
||||
for ( i=0; i < ap->a_numvals; i++ ) {
|
||||
rc = attr_valfind( a2, SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
|
||||
&ap->a_nvals[i], NULL, op->o_tmpmemctx );
|
||||
/* Save deleted values */
|
||||
if ( rc == LDAP_NO_SUCH_ATTRIBUTE )
|
||||
vals[j++] = ap->a_nvals[i];
|
||||
}
|
||||
BER_BVZERO(vals+j);
|
||||
} else {
|
||||
/* attribute was completely deleted */
|
||||
vals = ap->a_nvals;
|
||||
}
|
||||
rc = 0;
|
||||
if ( !BER_BVISNULL( vals )) {
|
||||
rc = mdb_index_values( op, tid, ap->a_desc,
|
||||
vals, e->e_id, SLAP_INDEX_DELETE_OP );
|
||||
if ( rc != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"%s: attribute \"%s\" index delete failure\n",
|
||||
op->o_log_prefix, ap->a_desc->ad_cname.bv_val, 0 );
|
||||
attrs_free( e->e_attrs );
|
||||
e->e_attrs = save_attrs;
|
||||
}
|
||||
}
|
||||
if ( vals != ap->a_nvals )
|
||||
op->o_tmpfree( vals, op->o_tmpmemctx );
|
||||
if ( rc ) return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* add the new index entries */
|
||||
for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
|
||||
if (ap->a_flags & SLAP_ATTR_IXADD) {
|
||||
ap->a_flags &= ~SLAP_ATTR_IXADD;
|
||||
rc = mdb_index_values( op, tid, ap->a_desc,
|
||||
ap->a_nvals,
|
||||
e->e_id, SLAP_INDEX_ADD_OP );
|
||||
if ( rc != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"%s: attribute \"%s\" index add failure\n",
|
||||
op->o_log_prefix, ap->a_desc->ad_cname.bv_val, 0 );
|
||||
attrs_free( e->e_attrs );
|
||||
e->e_attrs = save_attrs;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mdb_modify( Operation *op, SlapReply *rs )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
|
||||
Entry *e = NULL;
|
||||
int manageDSAit = get_manageDSAit( op );
|
||||
char textbuf[SLAP_TEXT_BUFLEN];
|
||||
size_t textlen = sizeof textbuf;
|
||||
MDB_txn *txn = NULL;
|
||||
mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;
|
||||
Entry dummy = {0};
|
||||
|
||||
LDAPControl **preread_ctrl = NULL;
|
||||
LDAPControl **postread_ctrl = NULL;
|
||||
LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
|
||||
int num_ctrls = 0;
|
||||
|
||||
#ifdef LDAP_X_TXN
|
||||
int settle = 0;
|
||||
#endif
|
||||
|
||||
Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(mdb_modify) ": %s\n",
|
||||
op->o_req_dn.bv_val, 0, 0 );
|
||||
|
||||
#ifdef LDAP_X_TXN
|
||||
if( op->o_txnSpec ) {
|
||||
/* acquire connection lock */
|
||||
ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
|
||||
if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
|
||||
rs->sr_text = "invalid transaction identifier";
|
||||
rs->sr_err = LDAP_X_TXN_ID_INVALID;
|
||||
goto txnReturn;
|
||||
} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
|
||||
settle=1;
|
||||
goto txnReturn;
|
||||
}
|
||||
|
||||
if( op->o_conn->c_txn_backend == NULL ) {
|
||||
op->o_conn->c_txn_backend = op->o_bd;
|
||||
|
||||
} else if( op->o_conn->c_txn_backend != op->o_bd ) {
|
||||
rs->sr_text = "transaction cannot span multiple database contexts";
|
||||
rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
|
||||
goto txnReturn;
|
||||
}
|
||||
|
||||
/* insert operation into transaction */
|
||||
|
||||
rs->sr_text = "transaction specified";
|
||||
rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
|
||||
|
||||
txnReturn:
|
||||
/* release connection lock */
|
||||
ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
|
||||
|
||||
if( !settle ) {
|
||||
send_ldap_result( op, rs );
|
||||
return rs->sr_err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ctrls[num_ctrls] = NULL;
|
||||
|
||||
/* Don't touch the opattrs, if this is a contextCSN update
|
||||
* initiated from updatedn */
|
||||
if ( !be_isupdate(op) || !op->orm_modlist || op->orm_modlist->sml_next ||
|
||||
op->orm_modlist->sml_desc != slap_schema.si_ad_contextCSN ) {
|
||||
|
||||
slap_mods_opattrs( op, &op->orm_modlist, 1 );
|
||||
}
|
||||
|
||||
/* begin transaction */
|
||||
rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi );
|
||||
rs->sr_text = NULL;
|
||||
if( rs->sr_err != 0 ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modify) ": txn_begin failed: "
|
||||
"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
txn = moi->moi_txn;
|
||||
|
||||
/* get entry or ancestor */
|
||||
rs->sr_err = mdb_dn2entry( op, txn, &op->o_req_ndn, &e, 1 );
|
||||
|
||||
if ( rs->sr_err != 0 ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modify) ": dn2entry failed (%d)\n",
|
||||
rs->sr_err, 0, 0 );
|
||||
switch( rs->sr_err ) {
|
||||
case MDB_NOTFOUND:
|
||||
break;
|
||||
case LDAP_BUSY:
|
||||
rs->sr_text = "ldap server busy";
|
||||
goto return_results;
|
||||
default:
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
}
|
||||
|
||||
/* acquire and lock entry */
|
||||
/* FIXME: dn2entry() should return non-glue entry */
|
||||
if (( rs->sr_err == MDB_NOTFOUND ) ||
|
||||
( !manageDSAit && e && is_entry_glue( e )))
|
||||
{
|
||||
if ( e != NULL ) {
|
||||
rs->sr_matched = ch_strdup( e->e_dn );
|
||||
if ( is_entry_referral( e )) {
|
||||
BerVarray ref = get_entry_referrals( op, e );
|
||||
rs->sr_ref = referral_rewrite( ref, &e->e_name,
|
||||
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
|
||||
ber_bvarray_free( ref );
|
||||
} else {
|
||||
rs->sr_ref = NULL;
|
||||
}
|
||||
mdb_entry_return( e );
|
||||
e = NULL;
|
||||
|
||||
} else {
|
||||
rs->sr_ref = referral_rewrite( default_referral, NULL,
|
||||
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
|
||||
}
|
||||
|
||||
rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
|
||||
rs->sr_err = LDAP_REFERRAL;
|
||||
send_ldap_result( op, rs );
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( !manageDSAit && is_entry_referral( e ) ) {
|
||||
/* entry is a referral, don't allow modify */
|
||||
rs->sr_ref = get_entry_referrals( op, e );
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modify) ": entry is referral\n",
|
||||
0, 0, 0 );
|
||||
|
||||
rs->sr_err = LDAP_REFERRAL;
|
||||
rs->sr_matched = e->e_name.bv_val;
|
||||
rs->sr_flags = REP_REF_MUSTBEFREED;
|
||||
send_ldap_result( op, rs );
|
||||
rs->sr_matched = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( get_assert( op ) &&
|
||||
( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
|
||||
{
|
||||
rs->sr_err = LDAP_ASSERTION_FAILED;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
if( op->o_preread ) {
|
||||
if( preread_ctrl == NULL ) {
|
||||
preread_ctrl = &ctrls[num_ctrls++];
|
||||
ctrls[num_ctrls] = NULL;
|
||||
}
|
||||
if ( slap_read_controls( op, rs, e,
|
||||
&slap_pre_read_bv, preread_ctrl ) )
|
||||
{
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_modify) ": pre-read "
|
||||
"failed!\n", 0, 0, 0 );
|
||||
if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
|
||||
/* FIXME: is it correct to abort
|
||||
* operation if control fails? */
|
||||
goto return_results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Modify the entry */
|
||||
dummy = *e;
|
||||
rs->sr_err = mdb_modify_internal( op, txn, op->orm_modlist,
|
||||
&dummy, &rs->sr_text, textbuf, textlen );
|
||||
|
||||
if( rs->sr_err != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modify) ": modify failed (%d)\n",
|
||||
rs->sr_err, 0, 0 );
|
||||
/* Only free attrs if they were dup'd. */
|
||||
if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* change the entry itself */
|
||||
rs->sr_err = mdb_id2entry_update( op, txn, &dummy );
|
||||
if ( rs->sr_err != 0 ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modify) ": id2entry update failed " "(%d)\n",
|
||||
rs->sr_err, 0, 0 );
|
||||
rs->sr_text = "entry update failed";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
if( op->o_postread ) {
|
||||
if( postread_ctrl == NULL ) {
|
||||
postread_ctrl = &ctrls[num_ctrls++];
|
||||
ctrls[num_ctrls] = NULL;
|
||||
}
|
||||
if( slap_read_controls( op, rs, &dummy,
|
||||
&slap_post_read_bv, postread_ctrl ) )
|
||||
{
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_modify)
|
||||
": post-read failed!\n", 0, 0, 0 );
|
||||
if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
|
||||
/* FIXME: is it correct to abort
|
||||
* operation if control fails? */
|
||||
goto return_results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Only free attrs if they were dup'd. */
|
||||
if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
|
||||
if( moi == &opinfo ) {
|
||||
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
|
||||
opinfo.moi_oe.oe_key = NULL;
|
||||
if( op->o_noop ) {
|
||||
mdb_txn_abort( txn );
|
||||
rs->sr_err = LDAP_X_NO_OPERATION;
|
||||
txn = NULL;
|
||||
goto return_results;
|
||||
} else {
|
||||
rs->sr_err = mdb_txn_commit( txn );
|
||||
txn = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if( rs->sr_err != 0 ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modify) ": txn_%s failed: %s (%d)\n",
|
||||
op->o_noop ? "abort (no-op)" : "commit",
|
||||
mdb_strerror(rs->sr_err), rs->sr_err );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "commit failed";
|
||||
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modify) ": updated%s id=%08lx dn=\"%s\"\n",
|
||||
op->o_noop ? " (no-op)" : "",
|
||||
dummy.e_id, op->o_req_dn.bv_val );
|
||||
|
||||
rs->sr_err = LDAP_SUCCESS;
|
||||
rs->sr_text = NULL;
|
||||
if( num_ctrls ) rs->sr_ctrls = ctrls;
|
||||
|
||||
return_results:
|
||||
if( dummy.e_attrs ) {
|
||||
attrs_free( dummy.e_attrs );
|
||||
}
|
||||
send_ldap_result( op, rs );
|
||||
|
||||
#if 0
|
||||
if( rs->sr_err == LDAP_SUCCESS && mdb->bi_txn_cp_kbyte ) {
|
||||
TXN_CHECKPOINT( mdb->bi_dbenv,
|
||||
mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
done:
|
||||
slap_graduate_commit_csn( op );
|
||||
|
||||
if( moi == &opinfo ) {
|
||||
if( txn != NULL ) {
|
||||
mdb_txn_abort( txn );
|
||||
}
|
||||
if ( opinfo.moi_oe.oe_key ) {
|
||||
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
|
||||
}
|
||||
}
|
||||
|
||||
if( e != NULL ) {
|
||||
mdb_entry_return( e );
|
||||
}
|
||||
|
||||
if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
|
||||
slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
|
||||
slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
|
||||
}
|
||||
if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
|
||||
slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
|
||||
slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
|
||||
}
|
||||
|
||||
rs->sr_text = NULL;
|
||||
|
||||
return rs->sr_err;
|
||||
}
|
||||
655
servers/slapd/back-mdb/modrdn.c
Normal file
655
servers/slapd/back-mdb/modrdn.c
Normal file
|
|
@ -0,0 +1,655 @@
|
|||
/* modrdn.c - mdb backend modrdn routine */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ac/string.h>
|
||||
|
||||
#include "back-mdb.h"
|
||||
|
||||
int
|
||||
mdb_modrdn( Operation *op, SlapReply *rs )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
|
||||
AttributeDescription *children = slap_schema.si_ad_children;
|
||||
AttributeDescription *entry = slap_schema.si_ad_entry;
|
||||
struct berval p_dn, p_ndn;
|
||||
struct berval new_dn = {0, NULL}, new_ndn = {0, NULL};
|
||||
Entry *e = NULL;
|
||||
Entry *p = NULL;
|
||||
/* LDAP v2 supporting correct attribute handling. */
|
||||
char textbuf[SLAP_TEXT_BUFLEN];
|
||||
size_t textlen = sizeof textbuf;
|
||||
MDB_txn *txn = NULL;
|
||||
struct mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;
|
||||
Entry dummy = {0};
|
||||
|
||||
Entry *np = NULL; /* newSuperior Entry */
|
||||
struct berval *np_dn = NULL; /* newSuperior dn */
|
||||
struct berval *np_ndn = NULL; /* newSuperior ndn */
|
||||
struct berval *new_parent_dn = NULL; /* np_dn, p_dn, or NULL */
|
||||
|
||||
int manageDSAit = get_manageDSAit( op );
|
||||
|
||||
ID nid;
|
||||
LDAPControl **preread_ctrl = NULL;
|
||||
LDAPControl **postread_ctrl = NULL;
|
||||
LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
|
||||
int num_ctrls = 0;
|
||||
|
||||
int parent_is_glue = 0;
|
||||
int parent_is_leaf = 0;
|
||||
|
||||
#ifdef LDAP_X_TXN
|
||||
int settle = 0;
|
||||
#endif
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "==>" LDAP_XSTRING(mdb_modrdn) "(%s,%s,%s)\n",
|
||||
op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val,
|
||||
op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" );
|
||||
|
||||
#ifdef LDAP_X_TXN
|
||||
if( op->o_txnSpec ) {
|
||||
/* acquire connection lock */
|
||||
ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
|
||||
if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
|
||||
rs->sr_text = "invalid transaction identifier";
|
||||
rs->sr_err = LDAP_X_TXN_ID_INVALID;
|
||||
goto txnReturn;
|
||||
} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
|
||||
settle=1;
|
||||
goto txnReturn;
|
||||
}
|
||||
|
||||
if( op->o_conn->c_txn_backend == NULL ) {
|
||||
op->o_conn->c_txn_backend = op->o_bd;
|
||||
|
||||
} else if( op->o_conn->c_txn_backend != op->o_bd ) {
|
||||
rs->sr_text = "transaction cannot span multiple database contexts";
|
||||
rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
|
||||
goto txnReturn;
|
||||
}
|
||||
|
||||
/* insert operation into transaction */
|
||||
|
||||
rs->sr_text = "transaction specified";
|
||||
rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
|
||||
|
||||
txnReturn:
|
||||
/* release connection lock */
|
||||
ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
|
||||
|
||||
if( !settle ) {
|
||||
send_ldap_result( op, rs );
|
||||
return rs->sr_err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ctrls[num_ctrls] = NULL;
|
||||
|
||||
slap_mods_opattrs( op, &op->orr_modlist, 1 );
|
||||
|
||||
/* begin transaction */
|
||||
rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi );
|
||||
rs->sr_text = NULL;
|
||||
if( rs->sr_err != 0 ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modrdn) ": txn_begin failed: "
|
||||
"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
txn = moi->moi_txn;
|
||||
|
||||
if ( be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
|
||||
#ifdef MDB_MULTIPLE_SUFFIXES
|
||||
/* Allow renaming one suffix entry to another */
|
||||
p_ndn = slap_empty_bv;
|
||||
#else
|
||||
/* There can only be one suffix entry */
|
||||
rs->sr_err = LDAP_NAMING_VIOLATION;
|
||||
rs->sr_text = "cannot rename suffix entry";
|
||||
goto return_results;
|
||||
#endif
|
||||
} else {
|
||||
dnParent( &op->o_req_ndn, &p_ndn );
|
||||
}
|
||||
np_ndn = &p_ndn;
|
||||
/* Make sure parent entry exist and we can write its
|
||||
* children.
|
||||
*/
|
||||
rs->sr_err = mdb_dn2entry( op, txn, &p_ndn, &p, 0 );
|
||||
switch( rs->sr_err ) {
|
||||
case MDB_NOTFOUND:
|
||||
Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn)
|
||||
": parent does not exist\n", 0, 0, 0);
|
||||
rs->sr_ref = referral_rewrite( default_referral, NULL,
|
||||
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
|
||||
rs->sr_err = LDAP_REFERRAL;
|
||||
|
||||
send_ldap_result( op, rs );
|
||||
|
||||
ber_bvarray_free( rs->sr_ref );
|
||||
goto done;
|
||||
case 0:
|
||||
break;
|
||||
case LDAP_BUSY:
|
||||
rs->sr_text = "ldap server busy";
|
||||
goto return_results;
|
||||
default:
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* check parent for "children" acl */
|
||||
rs->sr_err = access_allowed( op, p,
|
||||
children, NULL,
|
||||
op->oq_modrdn.rs_newSup == NULL ?
|
||||
ACL_WRITE : ACL_WDEL,
|
||||
NULL );
|
||||
|
||||
if ( ! rs->sr_err ) {
|
||||
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
||||
Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
|
||||
0, 0 );
|
||||
rs->sr_text = "no write access to parent's children";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modrdn) ": wr to children "
|
||||
"of entry %s OK\n", p_ndn.bv_val, 0, 0 );
|
||||
|
||||
if ( p_ndn.bv_val == slap_empty_bv.bv_val ) {
|
||||
p_dn = slap_empty_bv;
|
||||
} else {
|
||||
dnParent( &op->o_req_dn, &p_dn );
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modrdn) ": parent dn=%s\n",
|
||||
p_dn.bv_val, 0, 0 );
|
||||
|
||||
/* get entry */
|
||||
rs->sr_err = mdb_dn2entry( op, txn, &op->o_req_ndn, &e, 0 );
|
||||
switch( rs->sr_err ) {
|
||||
case MDB_NOTFOUND:
|
||||
e = p;
|
||||
p = NULL;
|
||||
case 0:
|
||||
break;
|
||||
case LDAP_BUSY:
|
||||
rs->sr_text = "ldap server busy";
|
||||
goto return_results;
|
||||
default:
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* FIXME: dn2entry() should return non-glue entry */
|
||||
if (( rs->sr_err == MDB_NOTFOUND ) ||
|
||||
( !manageDSAit && e && is_entry_glue( e )))
|
||||
{
|
||||
if( e != NULL ) {
|
||||
rs->sr_matched = ch_strdup( e->e_dn );
|
||||
if ( is_entry_referral( e )) {
|
||||
BerVarray ref = get_entry_referrals( op, e );
|
||||
rs->sr_ref = referral_rewrite( ref, &e->e_name,
|
||||
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
|
||||
ber_bvarray_free( ref );
|
||||
} else {
|
||||
rs->sr_ref = NULL;
|
||||
}
|
||||
mdb_entry_return( e );
|
||||
e = NULL;
|
||||
|
||||
} else {
|
||||
rs->sr_ref = referral_rewrite( default_referral, NULL,
|
||||
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
|
||||
}
|
||||
|
||||
rs->sr_err = LDAP_REFERRAL;
|
||||
send_ldap_result( op, rs );
|
||||
|
||||
ber_bvarray_free( rs->sr_ref );
|
||||
free( (char *)rs->sr_matched );
|
||||
rs->sr_ref = NULL;
|
||||
rs->sr_matched = NULL;
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( get_assert( op ) &&
|
||||
( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
|
||||
{
|
||||
rs->sr_err = LDAP_ASSERTION_FAILED;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* check write on old entry */
|
||||
rs->sr_err = access_allowed( op, e, entry, NULL, ACL_WRITE, NULL );
|
||||
if ( ! rs->sr_err ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
|
||||
0, 0 );
|
||||
rs->sr_text = "no write access to old entry";
|
||||
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
if (!manageDSAit && is_entry_referral( e ) ) {
|
||||
/* entry is a referral, don't allow rename */
|
||||
rs->sr_ref = get_entry_referrals( op, e );
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn)
|
||||
": entry %s is referral\n", e->e_dn, 0, 0 );
|
||||
|
||||
rs->sr_err = LDAP_REFERRAL,
|
||||
rs->sr_matched = e->e_name.bv_val;
|
||||
send_ldap_result( op, rs );
|
||||
|
||||
ber_bvarray_free( rs->sr_ref );
|
||||
rs->sr_ref = NULL;
|
||||
rs->sr_matched = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
new_parent_dn = &p_dn; /* New Parent unless newSuperior given */
|
||||
|
||||
if ( op->oq_modrdn.rs_newSup != NULL ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modrdn)
|
||||
": new parent \"%s\" requested...\n",
|
||||
op->oq_modrdn.rs_newSup->bv_val, 0, 0 );
|
||||
|
||||
/* newSuperior == oldParent? */
|
||||
if( dn_match( &p_ndn, op->oq_modrdn.rs_nnewSup ) ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "mdb_back_modrdn: "
|
||||
"new parent \"%s\" same as the old parent \"%s\"\n",
|
||||
op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 );
|
||||
op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */
|
||||
}
|
||||
}
|
||||
|
||||
/* There's a MDB_MULTIPLE_SUFFIXES case here that this code doesn't
|
||||
* support. E.g., two suffixes dc=foo,dc=com and dc=bar,dc=net.
|
||||
* We do not allow modDN
|
||||
* dc=foo,dc=com
|
||||
* newrdn dc=bar
|
||||
* newsup dc=net
|
||||
* and we probably should. But since MULTIPLE_SUFFIXES is deprecated
|
||||
* I'm ignoring this problem for now.
|
||||
*/
|
||||
if ( op->oq_modrdn.rs_newSup != NULL ) {
|
||||
if ( op->oq_modrdn.rs_newSup->bv_len ) {
|
||||
np_dn = op->oq_modrdn.rs_newSup;
|
||||
np_ndn = op->oq_modrdn.rs_nnewSup;
|
||||
|
||||
/* newSuperior == oldParent? - checked above */
|
||||
/* newSuperior == entry being moved?, if so ==> ERROR */
|
||||
if ( dnIsSuffix( np_ndn, &e->e_nname )) {
|
||||
rs->sr_err = LDAP_NO_SUCH_OBJECT;
|
||||
rs->sr_text = "new superior not found";
|
||||
goto return_results;
|
||||
}
|
||||
/* Get Entry with dn=newSuperior. Does newSuperior exist? */
|
||||
|
||||
rs->sr_err = mdb_dn2entry( op, txn, np_ndn, &np, 0 );
|
||||
|
||||
switch( rs->sr_err ) {
|
||||
case 0:
|
||||
break;
|
||||
case MDB_NOTFOUND:
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modrdn)
|
||||
": newSup(ndn=%s) not here!\n",
|
||||
np_ndn->bv_val, 0, 0);
|
||||
rs->sr_text = "new superior not found";
|
||||
rs->sr_err = LDAP_NO_SUCH_OBJECT;
|
||||
goto return_results;
|
||||
case LDAP_BUSY:
|
||||
rs->sr_text = "ldap server busy";
|
||||
goto return_results;
|
||||
default:
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* check newSuperior for "children" acl */
|
||||
rs->sr_err = access_allowed( op, np, children,
|
||||
NULL, ACL_WADD, NULL );
|
||||
|
||||
if( ! rs->sr_err ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modrdn)
|
||||
": no wr to newSup children\n",
|
||||
0, 0, 0 );
|
||||
rs->sr_text = "no write access to new superior's children";
|
||||
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modrdn)
|
||||
": wr to new parent OK np=%p, id=%ld\n",
|
||||
(void *) np, (long) np->e_id, 0 );
|
||||
|
||||
if ( is_entry_alias( np ) ) {
|
||||
/* parent is an alias, don't allow add */
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modrdn)
|
||||
": entry is alias\n",
|
||||
0, 0, 0 );
|
||||
rs->sr_text = "new superior is an alias";
|
||||
rs->sr_err = LDAP_ALIAS_PROBLEM;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
if ( is_entry_referral( np ) ) {
|
||||
/* parent is a referral, don't allow add */
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modrdn)
|
||||
": entry is referral\n",
|
||||
0, 0, 0 );
|
||||
rs->sr_text = "new superior is a referral";
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
goto return_results;
|
||||
}
|
||||
new_parent_dn = &np->e_name;
|
||||
|
||||
} else {
|
||||
np_dn = NULL;
|
||||
|
||||
/* no parent, modrdn entry directly under root */
|
||||
if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
|
||||
|| be_isupdate( op ) ) {
|
||||
np = (Entry *)&slap_entry_root;
|
||||
|
||||
/* check parent for "children" acl */
|
||||
rs->sr_err = access_allowed( op, np,
|
||||
children, NULL, ACL_WADD, NULL );
|
||||
|
||||
np = NULL;
|
||||
|
||||
if ( ! rs->sr_err ) {
|
||||
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"no access to new superior\n",
|
||||
0, 0, 0 );
|
||||
rs->sr_text =
|
||||
"no write access to new superior's children";
|
||||
goto return_results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modrdn)
|
||||
": wr to new parent's children OK\n",
|
||||
0, 0, 0 );
|
||||
|
||||
new_parent_dn = np_dn;
|
||||
}
|
||||
|
||||
/* Build target dn and make sure target entry doesn't exist already. */
|
||||
if (!new_dn.bv_val) {
|
||||
build_new_dn( &new_dn, new_parent_dn, &op->oq_modrdn.rs_newrdn, op->o_tmpmemctx );
|
||||
}
|
||||
|
||||
if (!new_ndn.bv_val) {
|
||||
dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, op->o_tmpmemctx );
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn) ": new ndn=%s\n",
|
||||
new_ndn.bv_val, 0, 0 );
|
||||
|
||||
/* Shortcut the search */
|
||||
rs->sr_err = mdb_dn2id ( op, txn, &new_ndn, &nid, NULL, NULL );
|
||||
switch( rs->sr_err ) {
|
||||
case MDB_NOTFOUND:
|
||||
break;
|
||||
case 0:
|
||||
/* Allow rename to same DN */
|
||||
if ( nid == e->e_id )
|
||||
break;
|
||||
rs->sr_err = LDAP_ALREADY_EXISTS;
|
||||
goto return_results;
|
||||
default:
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
assert( op->orr_modlist != NULL );
|
||||
|
||||
if( op->o_preread ) {
|
||||
if( preread_ctrl == NULL ) {
|
||||
preread_ctrl = &ctrls[num_ctrls++];
|
||||
ctrls[num_ctrls] = NULL;
|
||||
}
|
||||
if( slap_read_controls( op, rs, e,
|
||||
&slap_pre_read_bv, preread_ctrl ) )
|
||||
{
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_modrdn)
|
||||
": pre-read failed!\n", 0, 0, 0 );
|
||||
if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
|
||||
/* FIXME: is it correct to abort
|
||||
* operation if control fails? */
|
||||
goto return_results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* delete old DN */
|
||||
rs->sr_err = mdb_dn2id_delete( op, txn, p->e_id, e );
|
||||
if ( rs->sr_err != 0 ) {
|
||||
Debug(LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_modrdn)
|
||||
": dn2id del failed: %s (%d)\n",
|
||||
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "DN index delete fail";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* copy the entry, then override some fields */
|
||||
dummy = *e;
|
||||
dummy.e_name = new_dn;
|
||||
dummy.e_nname = new_ndn;
|
||||
dummy.e_attrs = NULL;
|
||||
|
||||
/* add new DN */
|
||||
rs->sr_err = mdb_dn2id_add( op, txn, np ? np->e_id : p->e_id, &dummy );
|
||||
if ( rs->sr_err != 0 ) {
|
||||
Debug(LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_modrdn)
|
||||
": dn2id add failed: %s (%d)\n",
|
||||
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "DN index add failed";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
dummy.e_attrs = e->e_attrs;
|
||||
|
||||
/* modify entry */
|
||||
rs->sr_err = mdb_modify_internal( op, txn, op->orr_modlist, &dummy,
|
||||
&rs->sr_text, textbuf, textlen );
|
||||
if( rs->sr_err != LDAP_SUCCESS ) {
|
||||
Debug(LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_modrdn)
|
||||
": modify failed: %s (%d)\n",
|
||||
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
/* id2entry index */
|
||||
rs->sr_err = mdb_id2entry_update( op, txn, &dummy );
|
||||
if ( rs->sr_err != 0 ) {
|
||||
Debug(LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_modrdn)
|
||||
": id2entry failed: %s (%d)\n",
|
||||
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "entry update failed";
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
if ( p_ndn.bv_len != 0 ) {
|
||||
parent_is_glue = is_entry_glue(p);
|
||||
rs->sr_err = mdb_dn2id_children( op, txn, p );
|
||||
if ( rs->sr_err != MDB_NOTFOUND ) {
|
||||
switch( rs->sr_err ) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
Debug(LDAP_DEBUG_ARGS,
|
||||
"<=- " LDAP_XSTRING(mdb_modrdn)
|
||||
": has_children failed: %s (%d)\n",
|
||||
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
rs->sr_text = "internal error";
|
||||
goto return_results;
|
||||
}
|
||||
parent_is_leaf = 1;
|
||||
}
|
||||
mdb_entry_return( p );
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
if( op->o_postread ) {
|
||||
if( postread_ctrl == NULL ) {
|
||||
postread_ctrl = &ctrls[num_ctrls++];
|
||||
ctrls[num_ctrls] = NULL;
|
||||
}
|
||||
if( slap_read_controls( op, rs, &dummy,
|
||||
&slap_post_read_bv, postread_ctrl ) )
|
||||
{
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"<=- " LDAP_XSTRING(mdb_modrdn)
|
||||
": post-read failed!\n", 0, 0, 0 );
|
||||
if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
|
||||
/* FIXME: is it correct to abort
|
||||
* operation if control fails? */
|
||||
goto return_results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( moi == &opinfo ) {
|
||||
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
|
||||
opinfo.moi_oe.oe_key = NULL;
|
||||
if( op->o_noop ) {
|
||||
mdb_txn_abort( txn );
|
||||
rs->sr_err = LDAP_X_NO_OPERATION;
|
||||
txn = NULL;
|
||||
/* Only free attrs if they were dup'd. */
|
||||
if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
|
||||
goto return_results;
|
||||
|
||||
} else {
|
||||
if(( rs->sr_err=mdb_txn_commit( txn )) != 0 ) {
|
||||
rs->sr_text = "txn_commit failed";
|
||||
} else {
|
||||
rs->sr_err = LDAP_SUCCESS;
|
||||
}
|
||||
txn = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if( rs->sr_err != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modrdn) ": %s : %s (%d)\n",
|
||||
rs->sr_text, mdb_strerror(rs->sr_err), rs->sr_err );
|
||||
rs->sr_err = LDAP_OTHER;
|
||||
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_modrdn)
|
||||
": rdn modified%s id=%08lx dn=\"%s\"\n",
|
||||
op->o_noop ? " (no-op)" : "",
|
||||
dummy.e_id, op->o_req_dn.bv_val );
|
||||
rs->sr_text = NULL;
|
||||
if( num_ctrls ) rs->sr_ctrls = ctrls;
|
||||
|
||||
return_results:
|
||||
if ( dummy.e_attrs ) {
|
||||
attrs_free( dummy.e_attrs );
|
||||
}
|
||||
send_ldap_result( op, rs );
|
||||
|
||||
#if 0
|
||||
if( rs->sr_err == LDAP_SUCCESS && mdb->bi_txn_cp_kbyte ) {
|
||||
TXN_CHECKPOINT( mdb->bi_dbenv,
|
||||
mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
|
||||
op->o_delete_glue_parent = 1;
|
||||
}
|
||||
|
||||
done:
|
||||
slap_graduate_commit_csn( op );
|
||||
|
||||
if( new_ndn.bv_val != NULL ) op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
|
||||
if( new_dn.bv_val != NULL ) op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
|
||||
|
||||
/* LDAP v3 Support */
|
||||
if( np != NULL ) {
|
||||
/* free new parent */
|
||||
mdb_entry_return( np );
|
||||
}
|
||||
|
||||
if( p != NULL ) {
|
||||
/* free parent */
|
||||
mdb_entry_return( p );
|
||||
}
|
||||
|
||||
/* free entry */
|
||||
if( e != NULL ) {
|
||||
mdb_entry_return( e );
|
||||
}
|
||||
|
||||
if( moi == &opinfo ) {
|
||||
if( txn != NULL ) {
|
||||
mdb_txn_abort( txn );
|
||||
}
|
||||
if ( opinfo.moi_oe.oe_key ) {
|
||||
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
|
||||
}
|
||||
}
|
||||
|
||||
if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
|
||||
slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
|
||||
slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
|
||||
}
|
||||
if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
|
||||
slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
|
||||
slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
|
||||
}
|
||||
return rs->sr_err;
|
||||
}
|
||||
656
servers/slapd/back-mdb/monitor.c
Normal file
656
servers/slapd/back-mdb/monitor.c
Normal file
|
|
@ -0,0 +1,656 @@
|
|||
/* monitor.c - monitor mdb backend */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#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 "back-mdb.h"
|
||||
|
||||
#include "../back-monitor/back-monitor.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
static ObjectClass *oc_olmMDBDatabase;
|
||||
|
||||
static AttributeDescription *ad_olmDbDirectory;
|
||||
|
||||
#ifdef MDB_MONITOR_IDX
|
||||
static int
|
||||
mdb_monitor_idx_entry_add(
|
||||
struct mdb_info *mdb,
|
||||
Entry *e );
|
||||
|
||||
static AttributeDescription *ad_olmMDBNotIndexed;
|
||||
#endif /* MDB_MONITOR_IDX */
|
||||
|
||||
/*
|
||||
* 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
|
||||
* MDB database monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1.1
|
||||
*
|
||||
* 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
|
||||
* MDB database monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1.1
|
||||
*/
|
||||
|
||||
static struct {
|
||||
char *name;
|
||||
char *oid;
|
||||
} s_oid[] = {
|
||||
{ "olmMDBAttributes", "olmDatabaseAttributes:1" },
|
||||
{ "olmMDBObjectClasses", "olmDatabaseObjectClasses:1" },
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static struct {
|
||||
char *desc;
|
||||
AttributeDescription **ad;
|
||||
} s_at[] = {
|
||||
{ "( olmMDBAttributes:4 "
|
||||
"NAME ( 'olmDbDirectory' ) "
|
||||
"DESC 'Path name of the directory "
|
||||
"where the database environment resides' "
|
||||
"SUP monitoredInfo "
|
||||
"NO-USER-MODIFICATION "
|
||||
"USAGE dSAOperation )",
|
||||
&ad_olmDbDirectory },
|
||||
|
||||
#ifdef MDB_MONITOR_IDX
|
||||
{ "( olmMDBAttributes:5 "
|
||||
"NAME ( 'olmMDBNotIndexed' ) "
|
||||
"DESC 'Missing indexes resulting from candidate selection' "
|
||||
"SUP monitoredInfo "
|
||||
"NO-USER-MODIFICATION "
|
||||
"USAGE dSAOperation )",
|
||||
&ad_olmMDBNotIndexed },
|
||||
#endif /* MDB_MONITOR_IDX */
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static struct {
|
||||
char *desc;
|
||||
ObjectClass **oc;
|
||||
} s_oc[] = {
|
||||
/* augments an existing object, so it must be AUXILIARY
|
||||
* FIXME: derive from some ABSTRACT "monitoredEntity"? */
|
||||
{ "( olmMDBObjectClasses:2 "
|
||||
"NAME ( 'olmMDBDatabase' ) "
|
||||
"SUP top AUXILIARY "
|
||||
"MAY ( "
|
||||
"olmDbDirectory "
|
||||
#ifdef MDB_MONITOR_IDX
|
||||
"$ olmMDBNotIndexed "
|
||||
#endif /* MDB_MONITOR_IDX */
|
||||
") )",
|
||||
&oc_olmMDBDatabase },
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static int
|
||||
mdb_monitor_update(
|
||||
Operation *op,
|
||||
SlapReply *rs,
|
||||
Entry *e,
|
||||
void *priv )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) priv;
|
||||
|
||||
#ifdef MDB_MONITOR_IDX
|
||||
mdb_monitor_idx_entry_add( mdb, e );
|
||||
#endif /* MDB_MONITOR_IDX */
|
||||
|
||||
return SLAP_CB_CONTINUE;
|
||||
}
|
||||
|
||||
#if 0 /* uncomment if required */
|
||||
static int
|
||||
mdb_monitor_modify(
|
||||
Operation *op,
|
||||
SlapReply *rs,
|
||||
Entry *e,
|
||||
void *priv )
|
||||
{
|
||||
return SLAP_CB_CONTINUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
mdb_monitor_free(
|
||||
Entry *e,
|
||||
void **priv )
|
||||
{
|
||||
struct berval values[ 2 ];
|
||||
Modification mod = { 0 };
|
||||
|
||||
const char *text;
|
||||
char textbuf[ SLAP_TEXT_BUFLEN ];
|
||||
|
||||
int i, 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_olmMDBDatabase->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_numvals = 0;
|
||||
for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
|
||||
mod.sm_desc = *s_at[ i ].ad;
|
||||
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 mdb_initialize()
|
||||
*/
|
||||
static int
|
||||
mdb_monitor_initialize( void )
|
||||
{
|
||||
int i, code;
|
||||
ConfigArgs c;
|
||||
char *argv[ 3 ];
|
||||
|
||||
static int mdb_monitor_initialized = 0;
|
||||
|
||||
/* set to 0 when successfully initialized; otherwise, remember failure */
|
||||
static int mdb_monitor_initialized_failure = 1;
|
||||
|
||||
if ( mdb_monitor_initialized++ ) {
|
||||
return mdb_monitor_initialized_failure;
|
||||
}
|
||||
|
||||
if ( backend_info( "monitor" ) == NULL ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* register schema here */
|
||||
|
||||
argv[ 0 ] = "back-mdb monitor";
|
||||
c.argv = argv;
|
||||
c.argc = 3;
|
||||
c.fname = argv[0];
|
||||
|
||||
for ( i = 0; s_oid[ i ].name; i++ ) {
|
||||
c.lineno = i;
|
||||
argv[ 1 ] = s_oid[ i ].name;
|
||||
argv[ 2 ] = s_oid[ i ].oid;
|
||||
|
||||
if ( parse_oidm( &c, 0, NULL ) != 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
|
||||
": unable to add "
|
||||
"objectIdentifier \"%s=%s\"\n",
|
||||
s_oid[ i ].name, s_oid[ i ].oid, 0 );
|
||||
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, LDAP_XSTRING(mdb_monitor_initialize)
|
||||
": register_at failed for attributeType (%s)\n",
|
||||
s_at[ i ].desc, 0, 0 );
|
||||
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, LDAP_XSTRING(mdb_monitor_initialize)
|
||||
": register_oc failed for objectClass (%s)\n",
|
||||
s_oc[ i ].desc, 0, 0 );
|
||||
return 4;
|
||||
|
||||
} else {
|
||||
(*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE;
|
||||
}
|
||||
}
|
||||
|
||||
return ( mdb_monitor_initialized_failure = LDAP_SUCCESS );
|
||||
}
|
||||
|
||||
/*
|
||||
* call from within mdb_db_init()
|
||||
*/
|
||||
int
|
||||
mdb_monitor_db_init( BackendDB *be )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
|
||||
|
||||
if ( mdb_monitor_initialize() == LDAP_SUCCESS ) {
|
||||
/* monitoring in back-mdb is on by default */
|
||||
SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
|
||||
}
|
||||
|
||||
#ifdef MDB_MONITOR_IDX
|
||||
mdb->mi_idx = NULL;
|
||||
ldap_pvt_thread_mutex_init( &mdb->mi_idx_mutex );
|
||||
#endif /* MDB_MONITOR_IDX */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* call from within mdb_db_open()
|
||||
*/
|
||||
int
|
||||
mdb_monitor_db_open( BackendDB *be )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) be->be_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, LDAP_XSTRING(mdb_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 + 1 );
|
||||
if ( a == NULL ) {
|
||||
rc = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
a->a_desc = slap_schema.si_ad_objectClass;
|
||||
attr_valadd( a, &oc_olmMDBDatabase->soc_cname, NULL, 1 );
|
||||
next = a->a_next;
|
||||
|
||||
{
|
||||
struct berval bv, nbv;
|
||||
ber_len_t pathlen = 0, len = 0;
|
||||
char path[ MAXPATHLEN ] = { '\0' };
|
||||
char *fname = mdb->mi_dbenv_home,
|
||||
*ptr;
|
||||
|
||||
len = strlen( fname );
|
||||
if ( fname[ 0 ] != '/' ) {
|
||||
/* get full path name */
|
||||
getcwd( path, sizeof( path ) );
|
||||
pathlen = strlen( path );
|
||||
|
||||
if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) {
|
||||
fname += 2;
|
||||
len -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
bv.bv_len = pathlen + STRLENOF( "/" ) + len;
|
||||
ptr = bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 );
|
||||
if ( pathlen ) {
|
||||
ptr = lutil_strncopy( ptr, path, pathlen );
|
||||
ptr[ 0 ] = '/';
|
||||
ptr++;
|
||||
}
|
||||
ptr = lutil_strncopy( ptr, fname, len );
|
||||
if ( ptr[ -1 ] != '/' ) {
|
||||
ptr[ 0 ] = '/';
|
||||
ptr++;
|
||||
}
|
||||
ptr[ 0 ] = '\0';
|
||||
|
||||
attr_normalize_one( ad_olmDbDirectory, &bv, &nbv, NULL );
|
||||
|
||||
next->a_desc = ad_olmDbDirectory;
|
||||
next->a_vals = ch_calloc( sizeof( struct berval ), 2 );
|
||||
next->a_vals[ 0 ] = bv;
|
||||
next->a_numvals = 1;
|
||||
|
||||
if ( BER_BVISNULL( &nbv ) ) {
|
||||
next->a_nvals = next->a_vals;
|
||||
|
||||
} else {
|
||||
next->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
|
||||
next->a_nvals[ 0 ] = nbv;
|
||||
}
|
||||
|
||||
next = next->a_next;
|
||||
}
|
||||
|
||||
cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
|
||||
cb->mc_update = mdb_monitor_update;
|
||||
#if 0 /* uncomment if required */
|
||||
cb->mc_modify = mdb_monitor_modify;
|
||||
#endif
|
||||
cb->mc_free = mdb_monitor_free;
|
||||
cb->mc_private = (void *)mdb;
|
||||
|
||||
/* make sure the database is registered; then add monitor attributes */
|
||||
rc = mbe->register_database( be, &mdb->mi_monitor.mdm_ndn );
|
||||
if ( rc == 0 ) {
|
||||
rc = mbe->register_entry_attrs( &mdb->mi_monitor.mdm_ndn, a, cb,
|
||||
&dummy, 0, &dummy );
|
||||
}
|
||||
|
||||
cleanup:;
|
||||
if ( rc != 0 ) {
|
||||
if ( cb != NULL ) {
|
||||
ch_free( cb );
|
||||
cb = NULL;
|
||||
}
|
||||
|
||||
if ( a != NULL ) {
|
||||
attrs_free( a );
|
||||
a = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* store for cleanup */
|
||||
mdb->mi_monitor.mdm_cb = (void *)cb;
|
||||
|
||||
/* we don't need to keep track of the attributes, because
|
||||
* mdb_monitor_free() takes care of everything */
|
||||
if ( a != NULL ) {
|
||||
attrs_free( a );
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* call from within mdb_db_close()
|
||||
*/
|
||||
int
|
||||
mdb_monitor_db_close( BackendDB *be )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
|
||||
|
||||
if ( !BER_BVISNULL( &mdb->mi_monitor.mdm_ndn ) ) {
|
||||
BackendInfo *mi = backend_info( "monitor" );
|
||||
monitor_extra_t *mbe;
|
||||
|
||||
if ( mi && &mi->bi_extra ) {
|
||||
mbe = mi->bi_extra;
|
||||
mbe->unregister_entry_callback( &mdb->mi_monitor.mdm_ndn,
|
||||
(monitor_callback_t *)mdb->mi_monitor.mdm_cb,
|
||||
NULL, 0, NULL );
|
||||
}
|
||||
|
||||
memset( &mdb->mi_monitor, 0, sizeof( mdb->mi_monitor ) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* call from within mdb_db_destroy()
|
||||
*/
|
||||
int
|
||||
mdb_monitor_db_destroy( BackendDB *be )
|
||||
{
|
||||
#ifdef MDB_MONITOR_IDX
|
||||
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
|
||||
|
||||
/* TODO: free tree */
|
||||
ldap_pvt_thread_mutex_destroy( &mdb->mi_idx_mutex );
|
||||
avl_free( mdb->mi_idx, ch_free );
|
||||
#endif /* MDB_MONITOR_IDX */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MDB_MONITOR_IDX
|
||||
|
||||
#define MDB_MONITOR_IDX_TYPES (4)
|
||||
|
||||
typedef struct monitor_idx_t monitor_idx_t;
|
||||
|
||||
struct monitor_idx_t {
|
||||
AttributeDescription *idx_ad;
|
||||
unsigned long idx_count[MDB_MONITOR_IDX_TYPES];
|
||||
};
|
||||
|
||||
static int
|
||||
mdb_monitor_bitmask2key( slap_mask_t bitmask )
|
||||
{
|
||||
int key;
|
||||
|
||||
for ( key = 0; key < 8 * (int)sizeof(slap_mask_t) && !( bitmask & 0x1U );
|
||||
key++ )
|
||||
bitmask >>= 1;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static struct berval idxbv[] = {
|
||||
BER_BVC( "present=" ),
|
||||
BER_BVC( "equality=" ),
|
||||
BER_BVC( "approx=" ),
|
||||
BER_BVC( "substr=" ),
|
||||
BER_BVNULL
|
||||
};
|
||||
|
||||
static ber_len_t
|
||||
mdb_monitor_idx2len( monitor_idx_t *idx )
|
||||
{
|
||||
int i;
|
||||
ber_len_t len = 0;
|
||||
|
||||
for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
|
||||
if ( idx->idx_count[ i ] != 0 ) {
|
||||
len += idxbv[i].bv_len;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
monitor_idx_cmp( const void *p1, const void *p2 )
|
||||
{
|
||||
const monitor_idx_t *idx1 = (const monitor_idx_t *)p1;
|
||||
const monitor_idx_t *idx2 = (const monitor_idx_t *)p2;
|
||||
|
||||
return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad );
|
||||
}
|
||||
|
||||
static int
|
||||
monitor_idx_dup( void *p1, void *p2 )
|
||||
{
|
||||
monitor_idx_t *idx1 = (monitor_idx_t *)p1;
|
||||
monitor_idx_t *idx2 = (monitor_idx_t *)p2;
|
||||
|
||||
return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ) == 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
int
|
||||
mdb_monitor_idx_add(
|
||||
struct mdb_info *mdb,
|
||||
AttributeDescription *desc,
|
||||
slap_mask_t type )
|
||||
{
|
||||
monitor_idx_t idx_dummy = { 0 },
|
||||
*idx;
|
||||
int rc = 0, key;
|
||||
|
||||
idx_dummy.idx_ad = desc;
|
||||
key = mdb_monitor_bitmask2key( type ) - 1;
|
||||
if ( key >= MDB_MONITOR_IDX_TYPES ) {
|
||||
/* invalid index type */
|
||||
return -1;
|
||||
}
|
||||
|
||||
ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
|
||||
|
||||
idx = (monitor_idx_t *)avl_find( mdb->mi_idx,
|
||||
(caddr_t)&idx_dummy, monitor_idx_cmp );
|
||||
if ( idx == NULL ) {
|
||||
idx = (monitor_idx_t *)ch_calloc( sizeof( monitor_idx_t ), 1 );
|
||||
idx->idx_ad = desc;
|
||||
idx->idx_count[ key ] = 1;
|
||||
|
||||
switch ( avl_insert( &mdb->mi_idx, (caddr_t)idx,
|
||||
monitor_idx_cmp, monitor_idx_dup ) )
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
default:
|
||||
ch_free( idx );
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
idx->idx_count[ key ]++;
|
||||
}
|
||||
|
||||
ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
mdb_monitor_idx_apply( void *v_idx, void *v_valp )
|
||||
{
|
||||
monitor_idx_t *idx = (monitor_idx_t *)v_idx;
|
||||
BerVarray *valp = (BerVarray *)v_valp;
|
||||
|
||||
struct berval bv;
|
||||
char *ptr;
|
||||
char count_buf[ MDB_MONITOR_IDX_TYPES ][ SLAP_TEXT_BUFLEN ];
|
||||
ber_len_t count_len[ MDB_MONITOR_IDX_TYPES ],
|
||||
idx_len;
|
||||
int i, num = 0;
|
||||
|
||||
idx_len = mdb_monitor_idx2len( idx );
|
||||
|
||||
bv.bv_len = 0;
|
||||
for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
|
||||
if ( idx->idx_count[ i ] == 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
count_len[ i ] = snprintf( count_buf[ i ],
|
||||
sizeof( count_buf[ i ] ), "%lu", idx->idx_count[ i ] );
|
||||
bv.bv_len += count_len[ i ];
|
||||
num++;
|
||||
}
|
||||
|
||||
bv.bv_len += idx->idx_ad->ad_cname.bv_len
|
||||
+ num
|
||||
+ idx_len;
|
||||
ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 );
|
||||
ptr = lutil_strcopy( ptr, idx->idx_ad->ad_cname.bv_val );
|
||||
for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
|
||||
if ( idx->idx_count[ i ] == 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ptr[ 0 ] = '#';
|
||||
++ptr;
|
||||
ptr = lutil_strcopy( ptr, idxbv[ i ].bv_val );
|
||||
ptr = lutil_strcopy( ptr, count_buf[ i ] );
|
||||
}
|
||||
|
||||
ber_bvarray_add( valp, &bv );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mdb_monitor_idx_entry_add(
|
||||
struct mdb_info *mdb,
|
||||
Entry *e )
|
||||
{
|
||||
BerVarray vals = NULL;
|
||||
Attribute *a;
|
||||
|
||||
a = attr_find( e->e_attrs, ad_olmMDBNotIndexed );
|
||||
|
||||
ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
|
||||
|
||||
avl_apply( mdb->mi_idx, mdb_monitor_idx_apply,
|
||||
&vals, -1, AVL_INORDER );
|
||||
|
||||
ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
|
||||
|
||||
if ( vals != NULL ) {
|
||||
if ( a != NULL ) {
|
||||
assert( a->a_nvals == a->a_vals );
|
||||
|
||||
ber_bvarray_free( a->a_vals );
|
||||
|
||||
} else {
|
||||
Attribute **ap;
|
||||
|
||||
for ( ap = &e->e_attrs; *ap != NULL; ap = &(*ap)->a_next )
|
||||
;
|
||||
*ap = attr_alloc( ad_olmMDBNotIndexed );
|
||||
a = *ap;
|
||||
}
|
||||
a->a_vals = vals;
|
||||
a->a_nvals = a->a_vals;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* MDB_MONITOR_IDX */
|
||||
59
servers/slapd/back-mdb/nextid.c
Normal file
59
servers/slapd/back-mdb/nextid.c
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* init.c - initialize mdb backend */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ac/string.h>
|
||||
|
||||
#include "back-mdb.h"
|
||||
|
||||
int mdb_next_id( BackendDB *be, MDB_txn *tid, ID *out )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
|
||||
int rc;
|
||||
ID id = 0;
|
||||
MDB_val key;
|
||||
MDB_cursor *cursor;
|
||||
|
||||
/* Get a read cursor */
|
||||
rc = mdb_cursor_open( tid, mdb->mi_id2entry, &cursor );
|
||||
|
||||
if (rc == 0) {
|
||||
rc = mdb_cursor_get(cursor, &key, NULL, MDB_LAST);
|
||||
mdb_cursor_close(cursor);
|
||||
}
|
||||
|
||||
switch(rc) {
|
||||
case MDB_NOTFOUND:
|
||||
rc = 0;
|
||||
*out = 1;
|
||||
break;
|
||||
case 0:
|
||||
memcpy( &id, key.mv_data, sizeof( id ));
|
||||
*out = ++id;
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> mdb_next_id: get failed: %s (%d)\n",
|
||||
mdb_strerror(rc), rc, 0 );
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
return rc;
|
||||
}
|
||||
119
servers/slapd/back-mdb/operational.c
Normal file
119
servers/slapd/back-mdb/operational.c
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/* operational.c - mdb backend operational attributes function */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/string.h>
|
||||
#include <ac/socket.h>
|
||||
|
||||
#include "slap.h"
|
||||
#include "back-mdb.h"
|
||||
|
||||
/*
|
||||
* sets *hasSubordinates to LDAP_COMPARE_TRUE/LDAP_COMPARE_FALSE
|
||||
* if the entry has children or not.
|
||||
*/
|
||||
int
|
||||
mdb_hasSubordinates(
|
||||
Operation *op,
|
||||
Entry *e,
|
||||
int *hasSubordinates )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
|
||||
MDB_txn *rtxn;
|
||||
mdb_op_info opinfo = {0}, *moi = &opinfo;
|
||||
int rc;
|
||||
|
||||
assert( e != NULL );
|
||||
|
||||
rc = mdb_opinfo_get(op, mdb, 1, &moi);
|
||||
switch(rc) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
rtxn = moi->moi_txn;
|
||||
|
||||
rc = mdb_dn2id_children( op, rtxn, e );
|
||||
|
||||
switch( rc ) {
|
||||
case 0:
|
||||
*hasSubordinates = LDAP_COMPARE_TRUE;
|
||||
break;
|
||||
|
||||
case MDB_NOTFOUND:
|
||||
*hasSubordinates = LDAP_COMPARE_FALSE;
|
||||
rc = LDAP_SUCCESS;
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug(LDAP_DEBUG_ARGS,
|
||||
"<=- " LDAP_XSTRING(mdb_hasSubordinates)
|
||||
": has_children failed: %s (%d)\n",
|
||||
mdb_strerror(rc), rc, 0 );
|
||||
rc = LDAP_OTHER;
|
||||
}
|
||||
|
||||
done:;
|
||||
if ( moi == &opinfo ) {
|
||||
mdb_txn_reset( moi->moi_txn );
|
||||
LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* sets the supported operational attributes (if required)
|
||||
*/
|
||||
int
|
||||
mdb_operational(
|
||||
Operation *op,
|
||||
SlapReply *rs )
|
||||
{
|
||||
Attribute **ap;
|
||||
|
||||
assert( rs->sr_entry != NULL );
|
||||
|
||||
for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) {
|
||||
if ( (*ap)->a_desc == slap_schema.si_ad_hasSubordinates ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( *ap == NULL &&
|
||||
attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL &&
|
||||
( SLAP_OPATTRS( rs->sr_attr_flags ) ||
|
||||
ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) ) )
|
||||
{
|
||||
int hasSubordinates, rc;
|
||||
|
||||
rc = mdb_hasSubordinates( op, rs->sr_entry, &hasSubordinates );
|
||||
if ( rc == LDAP_SUCCESS ) {
|
||||
*ap = slap_operational_hasSubordinate( hasSubordinates == LDAP_COMPARE_TRUE );
|
||||
assert( *ap != NULL );
|
||||
|
||||
ap = &(*ap)->a_next;
|
||||
}
|
||||
}
|
||||
|
||||
return LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
376
servers/slapd/back-mdb/proto-mdb.h
Normal file
376
servers/slapd/back-mdb/proto-mdb.h
Normal file
|
|
@ -0,0 +1,376 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#ifndef _PROTO_MDB_H
|
||||
#define _PROTO_MDB_H
|
||||
|
||||
LDAP_BEGIN_DECL
|
||||
|
||||
#define MDB_UCTYPE "MDB"
|
||||
|
||||
/*
|
||||
* attr.c
|
||||
*/
|
||||
|
||||
AttrInfo *mdb_attr_mask( struct mdb_info *mdb,
|
||||
AttributeDescription *desc );
|
||||
|
||||
void mdb_attr_flush( struct mdb_info *mdb );
|
||||
|
||||
int mdb_attr_slot( struct mdb_info *mdb,
|
||||
AttributeDescription *desc, int *insert );
|
||||
|
||||
int mdb_attr_dbs_open( BackendDB *be, MDB_txn *txn, struct config_reply_s *cr );
|
||||
void mdb_attr_dbs_close( struct mdb_info *mdb, MDB_txn *txn );
|
||||
|
||||
int mdb_attr_index_config LDAP_P(( struct mdb_info *mdb,
|
||||
const char *fname, int lineno,
|
||||
int argc, char **argv, struct config_reply_s *cr ));
|
||||
|
||||
void mdb_attr_index_unparse LDAP_P(( struct mdb_info *mdb, BerVarray *bva ));
|
||||
void mdb_attr_index_destroy LDAP_P(( struct mdb_info *mdb ));
|
||||
void mdb_attr_index_free LDAP_P(( struct mdb_info *mdb,
|
||||
AttributeDescription *ad ));
|
||||
|
||||
void mdb_attr_info_free( AttrInfo *ai );
|
||||
|
||||
/*
|
||||
* config.c
|
||||
*/
|
||||
|
||||
int mdb_back_init_cf( BackendInfo *bi );
|
||||
|
||||
/*
|
||||
* dn2entry.c
|
||||
*/
|
||||
|
||||
int mdb_dn2entry LDAP_P(( Operation *op, MDB_txn *tid,
|
||||
struct berval *dn, Entry **e, int matched ));
|
||||
|
||||
/*
|
||||
* dn2id.c
|
||||
*/
|
||||
|
||||
int mdb_dn2id(
|
||||
Operation *op,
|
||||
MDB_txn *txn,
|
||||
struct berval *ndn,
|
||||
ID *id,
|
||||
struct berval *matched,
|
||||
struct berval *nmatched );
|
||||
|
||||
int mdb_dn2id_add(
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
ID pid,
|
||||
Entry *e );
|
||||
|
||||
int mdb_dn2id_delete(
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
ID pid,
|
||||
Entry *e );
|
||||
|
||||
int mdb_dn2id_children(
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
Entry *e );
|
||||
|
||||
int mdb_dn2sups (
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
struct berval *dn,
|
||||
ID *sups
|
||||
);
|
||||
|
||||
int mdb_dn2idl(
|
||||
Operation *op,
|
||||
MDB_txn *txn,
|
||||
struct berval *ndn,
|
||||
ID eid,
|
||||
ID *ids,
|
||||
ID *stack );
|
||||
|
||||
int mdb_dn2id_parent(
|
||||
Operation *op,
|
||||
MDB_txn *txn,
|
||||
ID eid,
|
||||
ID *idp );
|
||||
|
||||
int mdb_id2name(
|
||||
Operation *op,
|
||||
MDB_txn *txn,
|
||||
MDB_cursor **cursp,
|
||||
ID eid,
|
||||
struct berval *name,
|
||||
struct berval *nname);
|
||||
|
||||
int mdb_idscope(
|
||||
Operation *op,
|
||||
MDB_txn *txn,
|
||||
ID base,
|
||||
ID *ids,
|
||||
ID *res );
|
||||
|
||||
int mdb_idscopes(
|
||||
Operation *op,
|
||||
MDB_txn *txn,
|
||||
MDB_cursor **cursp,
|
||||
ID base,
|
||||
ID *scopes );
|
||||
|
||||
MDB_cmp_func mdb_dup_compare;
|
||||
|
||||
/*
|
||||
* filterentry.c
|
||||
*/
|
||||
|
||||
int mdb_filter_candidates(
|
||||
Operation *op,
|
||||
MDB_txn *txn,
|
||||
Filter *f,
|
||||
ID *ids,
|
||||
ID *tmp,
|
||||
ID *stack );
|
||||
|
||||
/*
|
||||
* id2entry.c
|
||||
*/
|
||||
|
||||
int mdb_id2entry_add(
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
Entry *e );
|
||||
|
||||
int mdb_id2entry_update(
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
Entry *e );
|
||||
|
||||
int mdb_id2entry_delete(
|
||||
BackendDB *be,
|
||||
MDB_txn *tid,
|
||||
Entry *e);
|
||||
|
||||
int mdb_id2entry(
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
ID id,
|
||||
Entry **e);
|
||||
|
||||
void mdb_entry_free ( Entry *e );
|
||||
int mdb_entry_return( Entry *e );
|
||||
BI_entry_release_rw mdb_entry_release;
|
||||
BI_entry_get_rw mdb_entry_get;
|
||||
|
||||
void mdb_reader_flush( MDB_env *env );
|
||||
int mdb_opinfo_get( Operation *op, struct mdb_info *mdb, int rdonly, mdb_op_info **moi );
|
||||
|
||||
/*
|
||||
* idl.c
|
||||
*/
|
||||
|
||||
unsigned mdb_idl_search( ID *ids, ID id );
|
||||
|
||||
int mdb_idl_fetch_key(
|
||||
BackendDB *be,
|
||||
MDB_txn *txn,
|
||||
MDB_dbi dbi,
|
||||
MDB_val *key,
|
||||
ID *ids,
|
||||
MDB_cursor **saved_cursor,
|
||||
int get_flag );
|
||||
|
||||
int mdb_idl_insert( ID *ids, ID id );
|
||||
|
||||
int mdb_idl_insert_key(
|
||||
BackendDB *be,
|
||||
MDB_txn *txn,
|
||||
MDB_dbi dbi,
|
||||
MDB_val *key,
|
||||
ID id );
|
||||
|
||||
int mdb_idl_delete_key(
|
||||
BackendDB *be,
|
||||
MDB_txn *txn,
|
||||
MDB_dbi dbi,
|
||||
MDB_val *key,
|
||||
ID id );
|
||||
|
||||
int
|
||||
mdb_idl_intersection(
|
||||
ID *a,
|
||||
ID *b );
|
||||
|
||||
int
|
||||
mdb_idl_union(
|
||||
ID *a,
|
||||
ID *b );
|
||||
|
||||
ID mdb_idl_first( ID *ids, ID *cursor );
|
||||
ID mdb_idl_next( ID *ids, ID *cursor );
|
||||
|
||||
void mdb_idl_sort( ID *ids, ID *tmp );
|
||||
int mdb_idl_append( ID *a, ID *b );
|
||||
int mdb_idl_append_one( ID *ids, ID id );
|
||||
|
||||
|
||||
/*
|
||||
* index.c
|
||||
*/
|
||||
|
||||
extern AttrInfo *
|
||||
mdb_index_mask LDAP_P((
|
||||
Backend *be,
|
||||
AttributeDescription *desc,
|
||||
struct berval *name ));
|
||||
|
||||
extern int
|
||||
mdb_index_param LDAP_P((
|
||||
Backend *be,
|
||||
AttributeDescription *desc,
|
||||
int ftype,
|
||||
MDB_dbi *dbi,
|
||||
slap_mask_t *mask,
|
||||
struct berval *prefix ));
|
||||
|
||||
extern int
|
||||
mdb_index_values LDAP_P((
|
||||
Operation *op,
|
||||
MDB_txn *txn,
|
||||
AttributeDescription *desc,
|
||||
BerVarray vals,
|
||||
ID id,
|
||||
int opid ));
|
||||
|
||||
extern int
|
||||
mdb_index_recset LDAP_P((
|
||||
struct mdb_info *mdb,
|
||||
Attribute *a,
|
||||
AttributeType *type,
|
||||
struct berval *tags,
|
||||
IndexRec *ir ));
|
||||
|
||||
extern int
|
||||
mdb_index_recrun LDAP_P((
|
||||
Operation *op,
|
||||
struct mdb_info *mdb,
|
||||
IndexRec *ir,
|
||||
ID id,
|
||||
int base ));
|
||||
|
||||
int mdb_index_entry LDAP_P(( Operation *op, MDB_txn *t, int r, Entry *e ));
|
||||
|
||||
#define mdb_index_entry_add(op,t,e) \
|
||||
mdb_index_entry((op),(t),SLAP_INDEX_ADD_OP,(e))
|
||||
#define mdb_index_entry_del(op,t,e) \
|
||||
mdb_index_entry((op),(t),SLAP_INDEX_DELETE_OP,(e))
|
||||
|
||||
/*
|
||||
* key.c
|
||||
*/
|
||||
|
||||
extern int
|
||||
mdb_key_read(
|
||||
Backend *be,
|
||||
MDB_txn *txn,
|
||||
MDB_dbi dbi,
|
||||
struct berval *k,
|
||||
ID *ids,
|
||||
MDB_cursor **saved_cursor,
|
||||
int get_flags );
|
||||
|
||||
extern int
|
||||
mdb_key_change(
|
||||
Backend *be,
|
||||
MDB_txn *txn,
|
||||
MDB_dbi dbi,
|
||||
struct berval *k,
|
||||
ID id,
|
||||
int op );
|
||||
|
||||
/*
|
||||
* nextid.c
|
||||
*/
|
||||
|
||||
int mdb_next_id( BackendDB *be, MDB_txn *tid, ID *id );
|
||||
|
||||
/*
|
||||
* modify.c
|
||||
*/
|
||||
|
||||
int mdb_modify_internal(
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
Modifications *modlist,
|
||||
Entry *e,
|
||||
const char **text,
|
||||
char *textbuf,
|
||||
size_t textlen );
|
||||
|
||||
/*
|
||||
* monitor.c
|
||||
*/
|
||||
|
||||
int mdb_monitor_db_init( BackendDB *be );
|
||||
int mdb_monitor_db_open( BackendDB *be );
|
||||
int mdb_monitor_db_close( BackendDB *be );
|
||||
int mdb_monitor_db_destroy( BackendDB *be );
|
||||
|
||||
#ifdef MDB_MONITOR_IDX
|
||||
int
|
||||
mdb_monitor_idx_add(
|
||||
struct mdb_info *mdb,
|
||||
AttributeDescription *desc,
|
||||
slap_mask_t type );
|
||||
#endif /* MDB_MONITOR_IDX */
|
||||
|
||||
/*
|
||||
* former external.h
|
||||
*/
|
||||
|
||||
extern BI_init mdb_back_initialize;
|
||||
|
||||
extern BI_db_config mdb_db_config;
|
||||
|
||||
extern BI_op_add mdb_add;
|
||||
extern BI_op_bind mdb_bind;
|
||||
extern BI_op_compare mdb_compare;
|
||||
extern BI_op_delete mdb_delete;
|
||||
extern BI_op_modify mdb_modify;
|
||||
extern BI_op_modrdn mdb_modrdn;
|
||||
extern BI_op_search mdb_search;
|
||||
extern BI_op_extended mdb_extended;
|
||||
|
||||
extern BI_chk_referrals mdb_referrals;
|
||||
|
||||
extern BI_operational mdb_operational;
|
||||
|
||||
extern BI_has_subordinates mdb_hasSubordinates;
|
||||
|
||||
/* tools.c */
|
||||
extern BI_tool_entry_open mdb_tool_entry_open;
|
||||
extern BI_tool_entry_close mdb_tool_entry_close;
|
||||
extern BI_tool_entry_first_x mdb_tool_entry_first_x;
|
||||
extern BI_tool_entry_next mdb_tool_entry_next;
|
||||
extern BI_tool_entry_get mdb_tool_entry_get;
|
||||
extern BI_tool_entry_put mdb_tool_entry_put;
|
||||
extern BI_tool_entry_reindex mdb_tool_entry_reindex;
|
||||
extern BI_tool_dn2id_get mdb_tool_dn2id_get;
|
||||
extern BI_tool_entry_modify mdb_tool_entry_modify;
|
||||
|
||||
LDAP_END_DECL
|
||||
|
||||
#endif /* _PROTO_MDB_H */
|
||||
149
servers/slapd/back-mdb/referral.c
Normal file
149
servers/slapd/back-mdb/referral.c
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/* referral.c - MDB backend referral handler */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
#include <stdio.h>
|
||||
#include <ac/string.h>
|
||||
|
||||
#include "back-mdb.h"
|
||||
|
||||
int
|
||||
mdb_referrals( Operation *op, SlapReply *rs )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
|
||||
Entry *e = NULL;
|
||||
int rc = LDAP_SUCCESS;
|
||||
|
||||
MDB_txn *rtxn;
|
||||
mdb_op_info opinfo = {0}, *moi = &opinfo;
|
||||
|
||||
if( op->o_tag == LDAP_REQ_SEARCH ) {
|
||||
/* let search take care of itself */
|
||||
return rc;
|
||||
}
|
||||
|
||||
if( get_manageDSAit( op ) ) {
|
||||
/* let op take care of DSA management */
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = mdb_opinfo_get(op, mdb, 1, &moi);
|
||||
switch(rc) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return LDAP_OTHER;
|
||||
}
|
||||
|
||||
rtxn = moi->moi_txn;
|
||||
|
||||
/* get entry */
|
||||
rc = mdb_dn2entry( op, rtxn, &op->o_req_ndn, &e, 1 );
|
||||
|
||||
switch(rc) {
|
||||
case MDB_NOTFOUND:
|
||||
case 0:
|
||||
break;
|
||||
case LDAP_BUSY:
|
||||
rs->sr_text = "ldap server busy";
|
||||
goto done;
|
||||
default:
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_referrals)
|
||||
": dn2entry failed: %s (%d)\n",
|
||||
mdb_strerror(rc), rc, 0 );
|
||||
rs->sr_text = "internal error";
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( rc == MDB_NOTFOUND ) {
|
||||
rc = LDAP_SUCCESS;
|
||||
rs->sr_matched = NULL;
|
||||
if ( e != NULL ) {
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_referrals)
|
||||
": tag=%lu target=\"%s\" matched=\"%s\"\n",
|
||||
(unsigned long)op->o_tag, op->o_req_dn.bv_val, e->e_name.bv_val );
|
||||
|
||||
if( is_entry_referral( e ) ) {
|
||||
BerVarray ref = get_entry_referrals( op, e );
|
||||
rc = LDAP_OTHER;
|
||||
rs->sr_ref = referral_rewrite( ref, &e->e_name,
|
||||
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
|
||||
ber_bvarray_free( ref );
|
||||
if ( rs->sr_ref ) {
|
||||
rs->sr_matched = ber_strdup_x(
|
||||
e->e_name.bv_val, op->o_tmpmemctx );
|
||||
}
|
||||
}
|
||||
|
||||
mdb_entry_return( e );
|
||||
e = NULL;
|
||||
}
|
||||
|
||||
if( rs->sr_ref != NULL ) {
|
||||
/* send referrals */
|
||||
rc = rs->sr_err = LDAP_REFERRAL;
|
||||
send_ldap_result( op, rs );
|
||||
ber_bvarray_free( rs->sr_ref );
|
||||
rs->sr_ref = NULL;
|
||||
} else if ( rc != LDAP_SUCCESS ) {
|
||||
rs->sr_text = rs->sr_matched ? "bad referral object" : NULL;
|
||||
}
|
||||
|
||||
if (rs->sr_matched) {
|
||||
op->o_tmpfree( (char *)rs->sr_matched, op->o_tmpmemctx );
|
||||
rs->sr_matched = NULL;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( is_entry_referral( e ) ) {
|
||||
/* entry is a referral */
|
||||
BerVarray refs = get_entry_referrals( op, e );
|
||||
rs->sr_ref = referral_rewrite(
|
||||
refs, &e->e_name, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
LDAP_XSTRING(mdb_referrals)
|
||||
": tag=%lu target=\"%s\" matched=\"%s\"\n",
|
||||
(unsigned long)op->o_tag, op->o_req_dn.bv_val, e->e_name.bv_val );
|
||||
|
||||
rs->sr_matched = e->e_name.bv_val;
|
||||
if( rs->sr_ref != NULL ) {
|
||||
rc = rs->sr_err = LDAP_REFERRAL;
|
||||
send_ldap_result( op, rs );
|
||||
ber_bvarray_free( rs->sr_ref );
|
||||
rs->sr_ref = NULL;
|
||||
} else {
|
||||
rc = LDAP_OTHER;
|
||||
rs->sr_text = "bad referral object";
|
||||
}
|
||||
|
||||
rs->sr_matched = NULL;
|
||||
ber_bvarray_free( refs );
|
||||
}
|
||||
|
||||
done:
|
||||
if ( moi == &opinfo ) {
|
||||
mdb_txn_reset( moi->moi_txn );
|
||||
LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
|
||||
}
|
||||
if ( e )
|
||||
mdb_entry_return( e );
|
||||
return rc;
|
||||
}
|
||||
1112
servers/slapd/back-mdb/search.c
Normal file
1112
servers/slapd/back-mdb/search.c
Normal file
File diff suppressed because it is too large
Load diff
875
servers/slapd/back-mdb/tools.c
Normal file
875
servers/slapd/back-mdb/tools.c
Normal file
|
|
@ -0,0 +1,875 @@
|
|||
/* tools.c - tools for slap tools */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2011 The OpenLDAP Foundation.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/errno.h>
|
||||
|
||||
#define AVL_INTERNAL
|
||||
#include "back-mdb.h"
|
||||
#include "idl.h"
|
||||
|
||||
static MDB_txn *txn = NULL, *txi = NULL;
|
||||
static MDB_cursor *cursor = NULL, *idcursor = NULL;
|
||||
static MDB_val key, data;
|
||||
static EntryHeader eh;
|
||||
static ID previd = NOID;
|
||||
|
||||
typedef struct dn_id {
|
||||
ID id;
|
||||
struct berval dn;
|
||||
} dn_id;
|
||||
|
||||
#define HOLE_SIZE 4096
|
||||
static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
|
||||
static unsigned nhmax = HOLE_SIZE;
|
||||
static unsigned nholes;
|
||||
|
||||
static struct berval *tool_base;
|
||||
static int tool_scope;
|
||||
static Filter *tool_filter;
|
||||
static Entry *tool_next_entry;
|
||||
|
||||
#if 0
|
||||
static ID mdb_tool_ix_id;
|
||||
static Operation *mdb_tool_ix_op;
|
||||
static int *mdb_tool_index_threads, mdb_tool_index_tcount;
|
||||
static void *mdb_tool_index_rec;
|
||||
static struct mdb_info *mdb_tool_info;
|
||||
static ldap_pvt_thread_mutex_t mdb_tool_index_mutex;
|
||||
static ldap_pvt_thread_cond_t mdb_tool_index_cond_main;
|
||||
static ldap_pvt_thread_cond_t mdb_tool_index_cond_work;
|
||||
static void * mdb_tool_index_task( void *ctx, void *ptr );
|
||||
#endif
|
||||
|
||||
static int mdb_writes, mdb_writes_per_commit;
|
||||
|
||||
static int
|
||||
mdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep );
|
||||
|
||||
int mdb_tool_entry_open(
|
||||
BackendDB *be, int mode )
|
||||
{
|
||||
/* In Quick mode, commit once per 1000 entries */
|
||||
mdb_writes = 0;
|
||||
if ( slapMode & SLAP_TOOL_QUICK )
|
||||
mdb_writes_per_commit = 1000;
|
||||
else
|
||||
mdb_writes_per_commit = 1;
|
||||
|
||||
#if 0
|
||||
/* Set up for threaded slapindex */
|
||||
if (( slapMode & (SLAP_TOOL_QUICK|SLAP_TOOL_READONLY)) == SLAP_TOOL_QUICK ) {
|
||||
if ( !mdb_tool_info ) {
|
||||
ldap_pvt_thread_mutex_init( &mdb_tool_index_mutex );
|
||||
ldap_pvt_thread_cond_init( &mdb_tool_index_cond_main );
|
||||
ldap_pvt_thread_cond_init( &mdb_tool_index_cond_work );
|
||||
if ( mdb->bi_nattrs ) {
|
||||
int i;
|
||||
mdb_tool_index_threads = ch_malloc( slap_tool_thread_max * sizeof( int ));
|
||||
mdb_tool_index_rec = ch_malloc( mdb->bi_nattrs * sizeof( IndexRec ));
|
||||
mdb_tool_index_tcount = slap_tool_thread_max - 1;
|
||||
for (i=1; i<slap_tool_thread_max; i++) {
|
||||
int *ptr = ch_malloc( sizeof( int ));
|
||||
*ptr = i;
|
||||
ldap_pvt_thread_pool_submit( &connection_pool,
|
||||
mdb_tool_index_task, ptr );
|
||||
}
|
||||
}
|
||||
mdb_tool_info = mdb;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdb_tool_entry_close(
|
||||
BackendDB *be )
|
||||
{
|
||||
#if 0
|
||||
if ( mdb_tool_info ) {
|
||||
slapd_shutdown = 1;
|
||||
ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
|
||||
|
||||
/* There might still be some threads starting */
|
||||
while ( mdb_tool_index_tcount ) {
|
||||
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
|
||||
&mdb_tool_index_mutex );
|
||||
}
|
||||
|
||||
mdb_tool_index_tcount = slap_tool_thread_max - 1;
|
||||
ldap_pvt_thread_cond_broadcast( &mdb_tool_index_cond_work );
|
||||
|
||||
/* Make sure all threads are stopped */
|
||||
while ( mdb_tool_index_tcount ) {
|
||||
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
|
||||
&mdb_tool_index_mutex );
|
||||
}
|
||||
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
|
||||
|
||||
mdb_tool_info = NULL;
|
||||
slapd_shutdown = 0;
|
||||
ch_free( mdb_tool_index_threads );
|
||||
ch_free( mdb_tool_index_rec );
|
||||
mdb_tool_index_tcount = slap_tool_thread_max - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( idcursor ) {
|
||||
mdb_cursor_close( idcursor );
|
||||
idcursor = NULL;
|
||||
}
|
||||
if( cursor ) {
|
||||
mdb_cursor_close( cursor );
|
||||
cursor = NULL;
|
||||
}
|
||||
if( txn ) {
|
||||
if ( mdb_txn_commit( txn ))
|
||||
return -1;
|
||||
txn = NULL;
|
||||
}
|
||||
|
||||
if( nholes ) {
|
||||
unsigned i;
|
||||
fprintf( stderr, "Error, entries missing!\n");
|
||||
for (i=0; i<nholes; i++) {
|
||||
fprintf(stderr, " entry %ld: %s\n",
|
||||
holes[i].id, holes[i].dn.bv_val);
|
||||
}
|
||||
nholes = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ID
|
||||
mdb_tool_entry_first_x(
|
||||
BackendDB *be,
|
||||
struct berval *base,
|
||||
int scope,
|
||||
Filter *f )
|
||||
{
|
||||
tool_base = base;
|
||||
tool_scope = scope;
|
||||
tool_filter = f;
|
||||
|
||||
return mdb_tool_entry_next( be );
|
||||
}
|
||||
|
||||
ID mdb_tool_entry_next(
|
||||
BackendDB *be )
|
||||
{
|
||||
int rc;
|
||||
ID id;
|
||||
struct mdb_info *mdb;
|
||||
|
||||
assert( be != NULL );
|
||||
assert( slapMode & SLAP_TOOL_MODE );
|
||||
|
||||
mdb = (struct mdb_info *) be->be_private;
|
||||
assert( mdb != NULL );
|
||||
|
||||
if ( !txn ) {
|
||||
rc = mdb_txn_begin( mdb->mi_dbenv, MDB_RDONLY, &txn );
|
||||
if ( rc )
|
||||
return NOID;
|
||||
rc = mdb_cursor_open( txn, mdb->mi_id2entry, &cursor );
|
||||
if ( rc ) {
|
||||
mdb_txn_abort( txn );
|
||||
return NOID;
|
||||
}
|
||||
}
|
||||
|
||||
next:;
|
||||
rc = mdb_cursor_get( cursor, &key, &data, MDB_NEXT );
|
||||
|
||||
if( rc ) {
|
||||
return NOID;
|
||||
}
|
||||
|
||||
previd = *(ID *)key.mv_data;
|
||||
id = previd;
|
||||
|
||||
if ( tool_filter || tool_base ) {
|
||||
static Operation op = {0};
|
||||
static Opheader ohdr = {0};
|
||||
|
||||
op.o_hdr = &ohdr;
|
||||
op.o_bd = be;
|
||||
op.o_tmpmemctx = NULL;
|
||||
op.o_tmpmfuncs = &ch_mfuncs;
|
||||
|
||||
if ( tool_next_entry ) {
|
||||
mdb_entry_release( &op, tool_next_entry, 0 );
|
||||
tool_next_entry = NULL;
|
||||
}
|
||||
|
||||
rc = mdb_tool_entry_get_int( be, id, &tool_next_entry );
|
||||
if ( rc == LDAP_NO_SUCH_OBJECT ) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
assert( tool_next_entry != NULL );
|
||||
|
||||
if ( tool_filter && test_filter( NULL, tool_next_entry, tool_filter ) != LDAP_COMPARE_TRUE )
|
||||
{
|
||||
mdb_entry_release( &op, tool_next_entry, 0 );
|
||||
tool_next_entry = NULL;
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
ID mdb_tool_dn2id_get(
|
||||
Backend *be,
|
||||
struct berval *dn
|
||||
)
|
||||
{
|
||||
struct mdb_info *mdb;
|
||||
Operation op = {0};
|
||||
Opheader ohdr = {0};
|
||||
ID id;
|
||||
int rc;
|
||||
|
||||
if ( BER_BVISEMPTY(dn) )
|
||||
return 0;
|
||||
|
||||
mdb = (struct mdb_info *) be->be_private;
|
||||
|
||||
if ( !txn ) {
|
||||
rc = mdb_txn_begin( mdb->mi_dbenv, (slapMode & SLAP_TOOL_READONLY) != 0 ?
|
||||
MDB_RDONLY : 0, &txn );
|
||||
if ( rc )
|
||||
return NOID;
|
||||
}
|
||||
|
||||
op.o_hdr = &ohdr;
|
||||
op.o_bd = be;
|
||||
op.o_tmpmemctx = NULL;
|
||||
op.o_tmpmfuncs = &ch_mfuncs;
|
||||
|
||||
rc = mdb_dn2id( &op, txn, dn, &id, NULL, NULL );
|
||||
if ( rc == MDB_NOTFOUND )
|
||||
return NOID;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static int
|
||||
mdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep )
|
||||
{
|
||||
Entry *e = NULL;
|
||||
struct berval dn = BER_BVNULL, ndn = BER_BVNULL;
|
||||
int rc;
|
||||
|
||||
assert( be != NULL );
|
||||
assert( slapMode & SLAP_TOOL_MODE );
|
||||
|
||||
if ( ( tool_filter || tool_base ) && id == previd && tool_next_entry != NULL ) {
|
||||
*ep = tool_next_entry;
|
||||
tool_next_entry = NULL;
|
||||
return LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
if ( id != previd ) {
|
||||
key.mv_size = sizeof(ID);
|
||||
key.mv_data = &id;
|
||||
rc = mdb_cursor_get( cursor, &key, &data, MDB_SET );
|
||||
if ( rc ) {
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if ( slapMode & SLAP_TOOL_READONLY ) {
|
||||
Operation op = {0};
|
||||
Opheader ohdr = {0};
|
||||
|
||||
op.o_hdr = &ohdr;
|
||||
op.o_bd = be;
|
||||
op.o_tmpmemctx = NULL;
|
||||
op.o_tmpmfuncs = &ch_mfuncs;
|
||||
|
||||
rc = mdb_id2name( &op, txn, &idcursor, id, &dn, &ndn );
|
||||
if ( rc ) {
|
||||
rc = LDAP_OTHER;
|
||||
mdb_entry_return( e );
|
||||
e = NULL;
|
||||
goto done;
|
||||
}
|
||||
if ( tool_base != NULL ) {
|
||||
if ( !dnIsSuffixScope( &ndn, tool_base, tool_scope ) ) {
|
||||
ch_free( dn.bv_val );
|
||||
ch_free( ndn.bv_val );
|
||||
rc = LDAP_NO_SUCH_OBJECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Get the header */
|
||||
eh.bv.bv_val = data.mv_data;
|
||||
eh.bv.bv_len = data.mv_size;
|
||||
|
||||
rc = entry_header( &eh );
|
||||
if ( rc ) {
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
eh.bv.bv_len = eh.nvals * sizeof( struct berval );
|
||||
eh.bv.bv_val = ch_malloc( eh.bv.bv_len );
|
||||
rc = entry_decode( &eh, &e );
|
||||
e->e_id = id;
|
||||
if ( !BER_BVISNULL( &dn )) {
|
||||
e->e_name = dn;
|
||||
e->e_nname = ndn;
|
||||
} else {
|
||||
e->e_name.bv_val = NULL;
|
||||
e->e_nname.bv_val = NULL;
|
||||
}
|
||||
e->e_bv = eh.bv;
|
||||
|
||||
done:
|
||||
if ( e != NULL ) {
|
||||
*ep = e;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Entry*
|
||||
mdb_tool_entry_get( BackendDB *be, ID id )
|
||||
{
|
||||
Entry *e = NULL;
|
||||
|
||||
(void)mdb_tool_entry_get_int( be, id, &e );
|
||||
return e;
|
||||
}
|
||||
|
||||
static int mdb_tool_next_id(
|
||||
Operation *op,
|
||||
MDB_txn *tid,
|
||||
Entry *e,
|
||||
struct berval *text,
|
||||
int hole )
|
||||
{
|
||||
struct berval dn = e->e_name;
|
||||
struct berval ndn = e->e_nname;
|
||||
struct berval pdn, npdn, nmatched;
|
||||
ID id, pid = 0;
|
||||
int rc;
|
||||
|
||||
if (ndn.bv_len == 0) {
|
||||
e->e_id = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = mdb_dn2id( op, tid, &ndn, &id, NULL, &nmatched );
|
||||
if ( rc == MDB_NOTFOUND ) {
|
||||
if ( !be_issuffix( op->o_bd, &ndn ) ) {
|
||||
ID eid = e->e_id;
|
||||
dnParent( &ndn, &npdn );
|
||||
if ( nmatched.bv_len != npdn.bv_len ) {
|
||||
dnParent( &dn, &pdn );
|
||||
e->e_name = pdn;
|
||||
e->e_nname = npdn;
|
||||
rc = mdb_tool_next_id( op, tid, e, text, 1 );
|
||||
e->e_name = dn;
|
||||
e->e_nname = ndn;
|
||||
if ( rc ) {
|
||||
return rc;
|
||||
}
|
||||
/* If parent didn't exist, it was created just now
|
||||
* and its ID is now in e->e_id. Make sure the current
|
||||
* entry gets added under the new parent ID.
|
||||
*/
|
||||
if ( eid != e->e_id ) {
|
||||
pid = e->e_id;
|
||||
}
|
||||
} else {
|
||||
pid = id;
|
||||
}
|
||||
}
|
||||
rc = mdb_next_id( op->o_bd, tid, &e->e_id );
|
||||
if ( rc ) {
|
||||
snprintf( text->bv_val, text->bv_len,
|
||||
"next_id failed: %s (%d)",
|
||||
mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> mdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
|
||||
return rc;
|
||||
}
|
||||
rc = mdb_dn2id_add( op, tid, pid, e );
|
||||
if ( rc ) {
|
||||
snprintf( text->bv_val, text->bv_len,
|
||||
"dn2id_add failed: %s (%d)",
|
||||
mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> mdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
|
||||
} else if ( hole ) {
|
||||
if ( nholes == nhmax - 1 ) {
|
||||
if ( holes == hbuf ) {
|
||||
holes = ch_malloc( nhmax * sizeof(dn_id) * 2 );
|
||||
AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
|
||||
} else {
|
||||
holes = ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
|
||||
}
|
||||
nhmax *= 2;
|
||||
}
|
||||
ber_dupbv( &holes[nholes].dn, &ndn );
|
||||
holes[nholes++].id = e->e_id;
|
||||
}
|
||||
} else if ( !hole ) {
|
||||
unsigned i, j;
|
||||
|
||||
e->e_id = id;
|
||||
|
||||
for ( i=0; i<nholes; i++) {
|
||||
if ( holes[i].id == e->e_id ) {
|
||||
free(holes[i].dn.bv_val);
|
||||
for (j=i;j<nholes;j++) holes[j] = holes[j+1];
|
||||
holes[j].id = 0;
|
||||
nholes--;
|
||||
break;
|
||||
} else if ( holes[i].id > e->e_id ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
mdb_tool_index_add(
|
||||
Operation *op,
|
||||
MDB_txn *txn,
|
||||
Entry *e )
|
||||
{
|
||||
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
|
||||
|
||||
if ( !mdb->mi_nattrs )
|
||||
return 0;
|
||||
|
||||
#if 0
|
||||
if ( slapMode & SLAP_TOOL_QUICK ) {
|
||||
IndexRec *ir;
|
||||
int i, rc;
|
||||
Attribute *a;
|
||||
|
||||
ir = mdb_tool_index_rec;
|
||||
memset(ir, 0, mdb->bi_nattrs * sizeof( IndexRec ));
|
||||
|
||||
for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
|
||||
rc = mdb_index_recset( mdb, a, a->a_desc->ad_type,
|
||||
&a->a_desc->ad_tags, ir );
|
||||
if ( rc )
|
||||
return rc;
|
||||
}
|
||||
mdb_tool_ix_id = e->e_id;
|
||||
mdb_tool_ix_op = op;
|
||||
ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
|
||||
/* Wait for all threads to be ready */
|
||||
while ( mdb_tool_index_tcount ) {
|
||||
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
|
||||
&mdb_tool_index_mutex );
|
||||
}
|
||||
for ( i=1; i<slap_tool_thread_max; i++ )
|
||||
mdb_tool_index_threads[i] = LDAP_BUSY;
|
||||
mdb_tool_index_tcount = slap_tool_thread_max - 1;
|
||||
ldap_pvt_thread_cond_broadcast( &mdb_tool_index_cond_work );
|
||||
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
|
||||
rc = mdb_index_recrun( op, mdb, ir, e->e_id, 0 );
|
||||
if ( rc )
|
||||
return rc;
|
||||
ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
|
||||
for ( i=1; i<slap_tool_thread_max; i++ ) {
|
||||
if ( mdb_tool_index_threads[i] == LDAP_BUSY ) {
|
||||
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
|
||||
&mdb_tool_index_mutex );
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
if ( mdb_tool_index_threads[i] ) {
|
||||
rc = mdb_tool_index_threads[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
|
||||
return rc;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return mdb_index_entry_add( op, txn, e );
|
||||
}
|
||||
}
|
||||
|
||||
ID mdb_tool_entry_put(
|
||||
BackendDB *be,
|
||||
Entry *e,
|
||||
struct berval *text )
|
||||
{
|
||||
int rc;
|
||||
struct mdb_info *mdb;
|
||||
Operation op = {0};
|
||||
Opheader ohdr = {0};
|
||||
|
||||
assert( be != NULL );
|
||||
assert( slapMode & SLAP_TOOL_MODE );
|
||||
|
||||
assert( text != NULL );
|
||||
assert( text->bv_val != NULL );
|
||||
assert( text->bv_val[0] == '\0' ); /* overconservative? */
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(mdb_tool_entry_put)
|
||||
"( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
|
||||
|
||||
mdb = (struct mdb_info *) be->be_private;
|
||||
|
||||
if ( !txn ) {
|
||||
rc = mdb_txn_begin( mdb->mi_dbenv, 0, &txn );
|
||||
if( rc != 0 ) {
|
||||
snprintf( text->bv_val, text->bv_len,
|
||||
"txn_begin failed: %s (%d)",
|
||||
mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
|
||||
text->bv_val, 0, 0 );
|
||||
return NOID;
|
||||
}
|
||||
}
|
||||
|
||||
op.o_hdr = &ohdr;
|
||||
op.o_bd = be;
|
||||
op.o_tmpmemctx = NULL;
|
||||
op.o_tmpmfuncs = &ch_mfuncs;
|
||||
|
||||
/* add dn2id indices */
|
||||
rc = mdb_tool_next_id( &op, txn, e, text, 0 );
|
||||
if( rc != 0 ) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = mdb_tool_index_add( &op, txn, e );
|
||||
if( rc != 0 ) {
|
||||
snprintf( text->bv_val, text->bv_len,
|
||||
"index_entry_add failed: %s (%d)",
|
||||
rc == LDAP_OTHER ? "Internal error" :
|
||||
mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
|
||||
text->bv_val, 0, 0 );
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
/* id2entry index */
|
||||
rc = mdb_id2entry_add( &op, txn, e );
|
||||
if( rc != 0 ) {
|
||||
snprintf( text->bv_val, text->bv_len,
|
||||
"id2entry_add failed: %s (%d)",
|
||||
mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
|
||||
text->bv_val, 0, 0 );
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
if( rc == 0 ) {
|
||||
mdb_writes++;
|
||||
if ( mdb_writes >= mdb_writes_per_commit ) {
|
||||
rc = mdb_txn_commit( txn );
|
||||
mdb_writes = 0;
|
||||
txn = NULL;
|
||||
if( rc != 0 ) {
|
||||
snprintf( text->bv_val, text->bv_len,
|
||||
"txn_commit failed: %s (%d)",
|
||||
mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
|
||||
text->bv_val, 0, 0 );
|
||||
e->e_id = NOID;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
mdb_txn_abort( txn );
|
||||
txn = NULL;
|
||||
snprintf( text->bv_val, text->bv_len,
|
||||
"txn_aborted! %s (%d)",
|
||||
rc == LDAP_OTHER ? "Internal error" :
|
||||
mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
|
||||
text->bv_val, 0, 0 );
|
||||
e->e_id = NOID;
|
||||
}
|
||||
|
||||
return e->e_id;
|
||||
}
|
||||
|
||||
int mdb_tool_entry_reindex(
|
||||
BackendDB *be,
|
||||
ID id,
|
||||
AttributeDescription **adv )
|
||||
{
|
||||
struct mdb_info *mi = (struct mdb_info *) be->be_private;
|
||||
int rc;
|
||||
Entry *e;
|
||||
Operation op = {0};
|
||||
Opheader ohdr = {0};
|
||||
|
||||
Debug( LDAP_DEBUG_ARGS,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_reindex) "( %ld )\n",
|
||||
(long) id, 0, 0 );
|
||||
assert( tool_base == NULL );
|
||||
assert( tool_filter == NULL );
|
||||
|
||||
/* No indexes configured, nothing to do. Could return an
|
||||
* error here to shortcut things.
|
||||
*/
|
||||
if (!mi->mi_attrs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for explicit list of attrs to index */
|
||||
if ( adv ) {
|
||||
int i, j, n;
|
||||
|
||||
if ( mi->mi_attrs[0]->ai_desc != adv[0] ) {
|
||||
/* count */
|
||||
for ( n = 0; adv[n]; n++ ) ;
|
||||
|
||||
/* insertion sort */
|
||||
for ( i = 0; i < n; i++ ) {
|
||||
AttributeDescription *ad = adv[i];
|
||||
for ( j = i-1; j>=0; j--) {
|
||||
if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
|
||||
adv[j+1] = adv[j];
|
||||
}
|
||||
adv[j+1] = ad;
|
||||
}
|
||||
}
|
||||
|
||||
for ( i = 0; adv[i]; i++ ) {
|
||||
if ( mi->mi_attrs[i]->ai_desc != adv[i] ) {
|
||||
for ( j = i+1; j < mi->mi_nattrs; j++ ) {
|
||||
if ( mi->mi_attrs[j]->ai_desc == adv[i] ) {
|
||||
AttrInfo *ai = mi->mi_attrs[i];
|
||||
mi->mi_attrs[i] = mi->mi_attrs[j];
|
||||
mi->mi_attrs[j] = ai;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( j == mi->mi_nattrs ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_tool_entry_reindex)
|
||||
": no index configured for %s\n",
|
||||
adv[i]->ad_cname.bv_val, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
mi->mi_nattrs = i;
|
||||
}
|
||||
|
||||
e = mdb_tool_entry_get( be, id );
|
||||
|
||||
if( e == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
LDAP_XSTRING(mdb_tool_entry_reindex)
|
||||
": could not locate id=%ld\n",
|
||||
(long) id, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( !txi ) {
|
||||
rc = mdb_txn_begin( mi->mi_dbenv, 0, &txi );
|
||||
if( rc != 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_reindex) ": "
|
||||
"txn_begin failed: %s (%d)\n",
|
||||
mdb_strerror(rc), rc, 0 );
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* just (re)add them for now
|
||||
* assume that some other routine (not yet implemented)
|
||||
* will zap index databases
|
||||
*
|
||||
*/
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_reindex) "( %ld, \"%s\" )\n",
|
||||
(long) id, e->e_dn, 0 );
|
||||
|
||||
op.o_hdr = &ohdr;
|
||||
op.o_bd = be;
|
||||
op.o_tmpmemctx = NULL;
|
||||
op.o_tmpmfuncs = &ch_mfuncs;
|
||||
|
||||
rc = mdb_tool_index_add( &op, txi, e );
|
||||
|
||||
done:
|
||||
if( rc == 0 ) {
|
||||
mdb_writes++;
|
||||
if ( mdb_writes >= mdb_writes_per_commit ) {
|
||||
rc = mdb_txn_commit( txi );
|
||||
if( rc != 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_reindex)
|
||||
": txn_commit failed: %s (%d)\n",
|
||||
mdb_strerror(rc), rc, 0 );
|
||||
e->e_id = NOID;
|
||||
}
|
||||
txi = NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
mdb_txn_abort( txi );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_reindex)
|
||||
": txn_aborted! %s (%d)\n",
|
||||
mdb_strerror(rc), rc, 0 );
|
||||
e->e_id = NOID;
|
||||
txi = NULL;
|
||||
}
|
||||
mdb_entry_release( &op, e, 0 );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
ID mdb_tool_entry_modify(
|
||||
BackendDB *be,
|
||||
Entry *e,
|
||||
struct berval *text )
|
||||
{
|
||||
int rc;
|
||||
struct mdb_info *mdb;
|
||||
MDB_txn *tid;
|
||||
Operation op = {0};
|
||||
Opheader ohdr = {0};
|
||||
|
||||
assert( be != NULL );
|
||||
assert( slapMode & SLAP_TOOL_MODE );
|
||||
|
||||
assert( text != NULL );
|
||||
assert( text->bv_val != NULL );
|
||||
assert( text->bv_val[0] == '\0' ); /* overconservative? */
|
||||
|
||||
assert ( e->e_id != NOID );
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_modify) "( %ld, \"%s\" )\n",
|
||||
(long) e->e_id, e->e_dn, 0 );
|
||||
|
||||
mdb = (struct mdb_info *) be->be_private;
|
||||
|
||||
if( cursor ) {
|
||||
mdb_cursor_close( cursor );
|
||||
cursor = NULL;
|
||||
}
|
||||
rc = mdb_txn_begin( mdb->mi_dbenv, 0, &tid );
|
||||
if( rc != 0 ) {
|
||||
snprintf( text->bv_val, text->bv_len,
|
||||
"txn_begin failed: %s (%d)",
|
||||
mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
|
||||
text->bv_val, 0, 0 );
|
||||
return NOID;
|
||||
}
|
||||
|
||||
op.o_hdr = &ohdr;
|
||||
op.o_bd = be;
|
||||
op.o_tmpmemctx = NULL;
|
||||
op.o_tmpmfuncs = &ch_mfuncs;
|
||||
|
||||
/* id2entry index */
|
||||
rc = mdb_id2entry_update( &op, tid, e );
|
||||
if( rc != 0 ) {
|
||||
snprintf( text->bv_val, text->bv_len,
|
||||
"id2entry_add failed: %s (%d)",
|
||||
mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
|
||||
text->bv_val, 0, 0 );
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
if( rc == 0 ) {
|
||||
rc = mdb_txn_commit( tid );
|
||||
if( rc != 0 ) {
|
||||
snprintf( text->bv_val, text->bv_len,
|
||||
"txn_commit failed: %s (%d)",
|
||||
mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": "
|
||||
"%s\n", text->bv_val, 0, 0 );
|
||||
e->e_id = NOID;
|
||||
}
|
||||
|
||||
} else {
|
||||
mdb_txn_abort( tid );
|
||||
snprintf( text->bv_val, text->bv_len,
|
||||
"txn_aborted! %s (%d)",
|
||||
mdb_strerror(rc), rc );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
|
||||
text->bv_val, 0, 0 );
|
||||
e->e_id = NOID;
|
||||
}
|
||||
|
||||
return e->e_id;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void *
|
||||
mdb_tool_index_task( void *ctx, void *ptr )
|
||||
{
|
||||
int base = *(int *)ptr;
|
||||
|
||||
free( ptr );
|
||||
while ( 1 ) {
|
||||
ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
|
||||
mdb_tool_index_tcount--;
|
||||
if ( !mdb_tool_index_tcount )
|
||||
ldap_pvt_thread_cond_signal( &mdb_tool_index_cond_main );
|
||||
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_work,
|
||||
&mdb_tool_index_mutex );
|
||||
if ( slapd_shutdown ) {
|
||||
mdb_tool_index_tcount--;
|
||||
if ( !mdb_tool_index_tcount )
|
||||
ldap_pvt_thread_cond_signal( &mdb_tool_index_cond_main );
|
||||
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
|
||||
break;
|
||||
}
|
||||
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
|
||||
|
||||
mdb_tool_index_threads[base] = mdb_index_recrun( mdb_tool_ix_op,
|
||||
mdb_tool_info, mdb_tool_index_rec, mdb_tool_ix_id, base );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
Loading…
Reference in a new issue