]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb2/modrdn.c
More timing for performance testing. Re-introduction of cache.c_mutex.
[openldap] / servers / slapd / back-bdb2 / modrdn.c
1 /* modrdn.c - bdb2 backend modrdn routine */
2
3 #include "portable.h"
4
5 #include <stdio.h>
6
7 #include <ac/string.h>
8 #include <ac/socket.h>
9
10 #include "slap.h"
11 #include "back-bdb2.h"
12 #include "proto-back-bdb2.h"
13
14 static int
15 bdb2i_back_modrdn_internal(
16     BackendDB   *be,
17     Connection  *conn,
18     Operation   *op,
19     char        *dn,
20     char        *newrdn,
21     int         deleteoldrdn
22 )
23 {
24         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
25         char            *matched = NULL;
26         char            *p_dn = NULL, *p_ndn = NULL;
27         char            *new_dn = NULL, *new_ndn = NULL;
28         char            sep[2];
29         Entry           *e, *p = NULL;
30         int                     rc = -1;
31
32         /* get entry with writer lock */
33         if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) {
34                 send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
35                 if ( matched != NULL ) {
36                         free( matched );
37                 }
38                 return( -1 );
39         }
40
41 #ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
42                 /* check parent for "children" acl */
43         if ( ! access_allowed( be, conn, op, e,
44                 "entry", NULL, ACL_WRITE ) )
45         {
46                 Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
47                         0, 0 );
48                 send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
49                         "", "" );
50                 goto return_results;
51         }
52 #endif
53
54         if ( (p_ndn = dn_parent( be, e->e_ndn )) != NULL ) {
55                 /* parent + rdn + separator(s) + null */
56                 if( (p = bdb2i_dn2entry_w( be, p_ndn, &matched )) == NULL) {
57                         Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
58                                 0, 0, 0);
59                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
60                                 "", "");
61                         goto return_results;
62                 }
63
64 #ifndef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
65                 /* check parent for "children" acl */
66                 if ( ! access_allowed( be, conn, op, p,
67                         "children", NULL, ACL_WRITE ) )
68                 {
69                         Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
70                                 0, 0 );
71                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
72                                 "", "" );
73                         goto return_results;
74                 }
75 #endif
76
77                 p_dn = dn_parent( be, e->e_dn );
78                 new_dn = (char *) ch_malloc( strlen( p_dn ) + strlen( newrdn )
79                     + 3 );
80                 if ( dn_type( e->e_dn ) == DN_X500 ) {
81                         strcpy( new_dn, newrdn );
82                         strcat( new_dn, "," );
83                         strcat( new_dn, p_dn );
84                 } else {
85                         char *s;
86                         strcpy( new_dn, newrdn );
87                         s = strchr( newrdn, '\0' );
88                         s--;
89                         if ( *s != '.' && *s != '@' ) {
90                                 if ( (s = strpbrk( dn, ".@" )) != NULL ) {
91                                         sep[0] = *s;
92                                         sep[1] = '\0';
93                                         strcat( new_dn, sep );
94                                 }
95                         }
96                         strcat( new_dn, p_dn );
97                 }
98
99         } else {
100                 /* no parent, modrdn entry directly under root */
101                 if( ! be_isroot( be, op->o_ndn ) ) {
102                         Debug( LDAP_DEBUG_TRACE, "no parent & not root\n",
103                                 0, 0, 0);
104                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
105                                 "", "");
106                         goto return_results;
107                 }
108
109                 new_dn = ch_strdup( newrdn );
110         }
111
112         new_ndn = dn_normalize_case( ch_strdup( new_dn ) );
113
114         if ( (bdb2i_dn2id ( be, new_ndn ) ) != NOID ) {
115                 send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL );
116                 goto return_results;
117         }
118
119         /* check for abandon */
120         ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
121         if ( op->o_abandon ) {
122                 ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
123                 goto return_results;
124         }
125         ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
126
127         /* add new one */
128         if ( bdb2i_dn2id_add( be, new_ndn, e->e_id ) != 0 ) {
129                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
130                 goto return_results;
131         }
132
133         /* delete old one */
134         if ( bdb2i_dn2id_delete( be, e->e_ndn ) != 0 ) {
135                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
136                 goto return_results;
137         }
138
139         (void) bdb2i_cache_delete_entry( &li->li_cache, e );
140         free( e->e_dn );
141         free( e->e_ndn );
142         e->e_dn = new_dn;
143         e->e_ndn = new_ndn;
144         (void) bdb2i_cache_update_entry( &li->li_cache, e );
145
146         /*
147          * At some point here we need to update the attribute values in
148          * the entry itself that were effected by this RDN change
149          * (respecting the value of the deleteoldrdn parameter).
150          *
151          * Since the code to do this has not yet been written, treat this
152          * omission as a (documented) bug.
153          */
154
155         /* id2entry index */
156         if ( bdb2i_id2entry_add( be, e ) != 0 ) {
157                 entry_free( e );
158                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
159                 goto return_results;
160         }
161
162         send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
163         rc = 0;
164
165 return_results:
166         if( new_dn != NULL ) free( new_dn );
167         if( new_ndn != NULL ) free( new_ndn );
168         if( p_dn != NULL ) free( p_dn );
169         if( p_ndn != NULL ) free( p_ndn );
170
171         if( matched != NULL ) free( matched );
172
173         if( p != NULL ) {
174                 /* free parent and writer lock */
175                 bdb2i_cache_return_entry_w( &li->li_cache, p );
176
177         }
178
179         /* free entry and writer lock */
180         bdb2i_cache_return_entry_w( &li->li_cache, e );
181         return( rc );
182 }
183
184
185 int
186 bdb2_back_modrdn(
187     BackendDB   *be,
188     Connection  *conn,
189     Operation   *op,
190     char        *dn,
191     char        *newrdn,
192     int         deleteoldrdn
193 )
194 {
195         DB_LOCK         lock;
196         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
197         struct timeval  time1;
198         int             ret;
199
200         bdb2i_start_timing( be->bd_info, &time1 );
201
202         if ( bdb2i_enter_backend_w( get_dbenv( be ), &lock ) != 0 ) {
203
204                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
205                 return( -1 );
206
207         }
208
209         ret = bdb2i_back_modrdn_internal( be, conn, op, dn,
210                                         newrdn, deleteoldrdn );
211
212         (void) bdb2i_leave_backend_w( get_dbenv( be ), lock );
213         bdb2i_stop_timing( be->bd_info, time1, "MODRDN", conn, op );
214
215         return( ret );
216 }
217
218