]> git.sur5r.net Git - openldap/blob - servers/slapd/repl.c
Fix replog sequencing - assign sequence numbers at beginning of operation,
[openldap] / servers / slapd / repl.c
1 /* repl.c - log modifications for replication purposes */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2003 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * provided that this notice is preserved and that due credit is given
21  * to the University of Michigan at Ann Arbor. The name of the University
22  * may not be used to endorse or promote products derived from this
23  * software without specific prior written permission. This software
24  * is provided ``as is'' without express or implied warranty.
25  */
26
27 #include "portable.h"
28
29 #include <stdio.h>
30
31 #include <ac/string.h>
32 #include <ac/ctype.h>
33 #include <ac/socket.h>
34
35 #ifdef HAVE_SYS_FILE_H
36 #include <sys/file.h>
37 #endif
38
39 #include "slap.h"
40 #include "ldif.h"
41
42 int
43 add_replica_info(
44     Backend     *be,
45     const char  *host 
46 )
47 {
48         int i = 0;
49
50         assert( be );
51         assert( host );
52
53         if ( be->be_replica != NULL ) {
54                 for ( ; be->be_replica[ i ] != NULL; i++ );
55         }
56                 
57         be->be_replica = ch_realloc( be->be_replica, 
58                 sizeof( struct slap_replica_info * )*( i + 2 ) );
59
60         be->be_replica[ i ] 
61                 = ch_calloc( sizeof( struct slap_replica_info ), 1 );
62         be->be_replica[ i ]->ri_host = ch_strdup( host );
63         be->be_replica[ i ]->ri_nsuffix = NULL;
64         be->be_replica[ i ]->ri_attrs = NULL;
65         be->be_replica[ i + 1 ] = NULL;
66
67         return( i );
68 }
69
70 int
71 add_replica_suffix(
72     Backend     *be,
73     int         nr,
74     const char  *suffix
75 )
76 {
77         struct berval dn, ndn;
78         int rc;
79
80         dn.bv_val = (char *) suffix;
81         dn.bv_len = strlen( dn.bv_val );
82
83         rc = dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL );
84         if( rc != LDAP_SUCCESS ) {
85                 return 2;
86         }
87
88         if ( select_backend( &ndn, 0, 0 ) != be ) {
89                 free( ndn.bv_val );
90                 return 1;
91         }
92
93         ber_bvarray_add( &be->be_replica[nr]->ri_nsuffix, &ndn );
94         return 0;
95 }
96
97 int
98 add_replica_attrs(
99         Backend *be,
100         int     nr,
101         char    *attrs,
102         int     exclude
103 )
104 {
105         if ( be->be_replica[nr]->ri_attrs != NULL ) {
106                 if ( be->be_replica[nr]->ri_exclude != exclude ) {
107                         fprintf( stderr, "attr selective replication directive '%s' conflicts with previous one (discarded)\n", attrs );
108                         ch_free( be->be_replica[nr]->ri_attrs );
109                         be->be_replica[nr]->ri_attrs = NULL;
110                 }
111         }
112
113         be->be_replica[nr]->ri_exclude = exclude;
114         be->be_replica[nr]->ri_attrs = str2anlist( be->be_replica[nr]->ri_attrs,
115                 attrs, "," );
116         return ( be->be_replica[nr]->ri_attrs == NULL );
117 }
118    
119 static struct timestamp {
120         long time;
121         long seq;
122 } oldstamp;
123
124 static void
125 print_vals( FILE *fp, struct berval *type, struct berval *bv );
126 static void
127 replog1( struct slap_replica_info *ri, Operation *op, FILE *fp );
128
129 void
130 repstamp( Operation *op )
131 {
132         ldap_pvt_thread_mutex_lock( &replog_mutex );
133         op->o_time = slap_get_time();
134         if ( op->o_time == oldstamp.time ) {
135                 op->o_tseq = ++oldstamp.seq;
136         } else {
137                 oldstamp.time = op->o_time;
138                 oldstamp.seq = 0;
139                 op->o_tseq = 0;
140         }
141         ldap_pvt_thread_mutex_unlock( &replog_mutex );
142 }
143
144 void
145 replog( Operation *op )
146 {
147         Modifications   *ml = NULL;
148         Attribute       *a = NULL;
149         FILE    *fp, *lfp;
150         int     i;
151 /* undef NO_LOG_WHEN_NO_REPLICAS */
152 #ifdef NO_LOG_WHEN_NO_REPLICAS
153         int     count = 0;
154 #endif
155         int     subsets = 0;
156
157         if ( op->o_bd->be_replogfile == NULL && replogfile == NULL ) {
158                 return;
159         }
160
161         ldap_pvt_thread_mutex_lock( &replog_mutex );
162         if ( (fp = lock_fopen( op->o_bd->be_replogfile ? op->o_bd->be_replogfile :
163             replogfile, "a", &lfp )) == NULL ) {
164                 ldap_pvt_thread_mutex_unlock( &replog_mutex );
165                 return;
166         }
167
168         for ( i = 0; op->o_bd->be_replica != NULL && op->o_bd->be_replica[i] != NULL; i++ ) {
169                 /* check if dn's suffix matches legal suffixes, if any */
170                 if ( op->o_bd->be_replica[i]->ri_nsuffix != NULL ) {
171                         int j;
172
173                         for ( j = 0; op->o_bd->be_replica[i]->ri_nsuffix[j].bv_val; j++ ) {
174                                 if ( dnIsSuffix( &op->o_req_ndn, &op->o_bd->be_replica[i]->ri_nsuffix[j] ) ) {
175                                         break;
176                                 }
177                         }
178
179                         if ( !op->o_bd->be_replica[i]->ri_nsuffix[j].bv_val ) {
180                                 /* do not add "replica:" line */
181                                 continue;
182                         }
183                 }
184                 /* See if we only want a subset of attributes */
185                 if ( op->o_bd->be_replica[i]->ri_attrs != NULL &&
186                         ( op->o_tag == LDAP_REQ_MODIFY || op->o_tag == LDAP_REQ_ADD || op->o_tag == LDAP_REQ_EXTENDED ) ) {
187                         if ( !subsets ) {
188                                 subsets = i + 1;
189                         }
190                         /* Do attribute subsets by themselves in a second pass */
191                         continue;
192                 }
193
194                 fprintf( fp, "replica: %s\n", op->o_bd->be_replica[i]->ri_host );
195 #ifdef NO_LOG_WHEN_NO_REPLICAS
196                 ++count;
197 #endif
198         }
199
200 #ifdef NO_LOG_WHEN_NO_REPLICAS
201         if ( count == 0 && subsets == 0 ) {
202                 /* if no replicas matched, drop the log 
203                  * (should we log it anyway?) */
204                 lock_fclose( fp, lfp );
205                 ldap_pvt_thread_mutex_unlock( &replog_mutex );
206
207                 return;
208         }
209 #endif
210
211         replog1( NULL, op, fp );
212
213         if ( subsets > 0 ) {
214                 for ( i = subsets - 1; op->o_bd->be_replica[i] != NULL; i++ ) {
215
216                         /* If no attrs, we already did this above */
217                         if ( op->o_bd->be_replica[i]->ri_attrs == NULL ) {
218                                 continue;
219                         }
220
221                         /* check if dn's suffix matches legal suffixes, if any */
222                         if ( op->o_bd->be_replica[i]->ri_nsuffix != NULL ) {
223                                 int j;
224
225                                 for ( j = 0; op->o_bd->be_replica[i]->ri_nsuffix[j].bv_val; j++ ) {
226                                         if ( dnIsSuffix( &op->o_req_ndn, &op->o_bd->be_replica[i]->ri_nsuffix[j] ) ) {
227                                                 break;
228                                         }
229                                 }
230
231                                 if ( !op->o_bd->be_replica[i]->ri_nsuffix[j].bv_val ) {
232                                         /* no matching suffix found, skip it */
233                                         continue;
234                                 }
235                         }
236                         switch( op->o_tag ) {
237                         case LDAP_REQ_EXTENDED:
238                                 /* quick hack for extended operations */
239                                 /* assume change parameter is a Modifications* */
240                                 /* fall thru */
241                         case LDAP_REQ_MODIFY:
242                         case LDAP_REQ_ADD:
243                                 break;
244                         default:
245                                 /* Other operations were logged in the first pass */
246                                 continue;
247                         }
248                         replog1( op->o_bd->be_replica[i], op, fp );
249                 }
250         }
251
252         lock_fclose( fp, lfp );
253         ldap_pvt_thread_mutex_unlock( &replog_mutex );
254 }
255
256 static void
257 rephdr(
258         struct slap_replica_info *ri,
259         Operation *op,
260         FILE *fp
261 )
262 {
263         if ( ri ) {
264                 fprintf( fp, "replica: %s\n", ri->ri_host );
265         }
266         fprintf( fp, "time: %ld.%ld\n", op->o_time, op->o_tseq );
267         fprintf( fp, "dn: %s\n", op->o_req_dn.bv_val );
268 }
269
270 static void
271 replog1(
272         struct slap_replica_info *ri,
273         Operation *op,
274         FILE    *fp
275 )
276 {
277         Modifications   *ml;
278         Attribute       *a;
279         AttributeName   *an;
280         int             dohdr = 1, ocs = -1;
281         struct berval vals[2];
282
283         vals[1].bv_val = NULL;
284         vals[1].bv_len = 0;
285
286         switch ( op->o_tag ) {
287         case LDAP_REQ_EXTENDED:
288                 /* quick hack for extended operations */
289                 /* assume change parameter is a Modifications* */
290                 /* fall thru */
291
292         case LDAP_REQ_MODIFY:
293                 for ( ml = op->orm_modlist; ml != NULL; ml = ml->sml_next ) {
294                         char *did, *type = ml->sml_desc->ad_cname.bv_val;
295                         switch ( ml->sml_op ) {
296                         case LDAP_MOD_ADD:
297                                 did = "add"; break;
298
299                         case LDAP_MOD_DELETE:
300                                 did = "delete"; break;
301
302                         case LDAP_MOD_REPLACE:
303                                 did = "replace"; break;
304
305                         case LDAP_MOD_INCREMENT:
306                                 did = "increment"; break;
307                         }
308                         if ( ri && ri->ri_attrs ) {
309                                 int is_in = ad_inlist( ml->sml_desc, ri->ri_attrs );
310
311                                 if ( ( !is_in && !ri->ri_exclude )
312                                         || ( is_in && ri->ri_exclude ) )
313                                 {
314                                         continue;
315                                 }
316                                 /* If this is objectClass, see if the value is included
317                                  * in any subset, otherwise drop it.
318                                  */
319                                 if ( ocs && ml->sml_desc == slap_schema.si_ad_objectClass
320                                         && ml->sml_bvalues ) {
321                                         int i, first = 1;
322
323                                         if ( ocs == -1 ) ocs = 0;
324
325                                         for ( i=0; ml->sml_bvalues[i].bv_val; i++ ) {
326                                                 int match = 0;
327                                                 for ( an = ri->ri_attrs; an->an_name.bv_val; an++ ) {
328                                                         if ( an->an_oc ) {
329                                                                 ocs = 1;
330                                                                 match |= an->an_oc_exclude;
331                                                                 if ( ml->sml_bvalues[i].bv_len == an->an_name.bv_len
332                                                                         && !strcasecmp(ml->sml_bvalues[i].bv_val,
333                                                                                 an->an_name.bv_val ) ) {
334                                                                         match = !an->an_oc_exclude;
335                                                                         break;
336                                                                 }
337                                                         }
338                                                 }
339                                                 /* Objectclasses need no special treatment, drop into
340                                                  * regular processing
341                                                  */
342                                                 if ( !ocs ) break;
343
344                                                 match ^= ri->ri_exclude;
345                                                 /* Found a match, log it */
346                                                 if ( match ) {
347                                                         if ( dohdr ) {
348                                                                 rephdr( ri, op, fp );
349                                                                 fprintf( fp, "changetype: modify\n" );
350                                                                 dohdr = 0;
351                                                         }
352                                                         if ( first ) {
353                                                                 fprintf( fp, "%s: %s\n", did, type );
354                                                                 first = 0;
355                                                         }
356                                                         vals[0] = an->an_name;
357                                                         print_vals( fp, &ml->sml_desc->ad_cname, vals );
358                                                         ocs = 2;
359                                                 }
360
361                                         }
362                                         /* Explicit objectclasses have been handled already */
363                                         if ( ocs ) {
364                                                 if ( ocs == 2 ) {
365                                                         fprintf( fp, "-\n" );
366                                                 }
367                                                 continue;
368                                         }
369                                 }
370                         }
371                         if ( dohdr ) {
372                                 rephdr( ri, op, fp );
373                                 fprintf( fp, "changetype: modify\n" );
374                                 dohdr = 0;
375                         }
376                         fprintf( fp, "%s: %s\n", did, type );
377                         if ( ml->sml_bvalues ) {
378                                 print_vals( fp, &ml->sml_desc->ad_cname, ml->sml_bvalues );
379                         }
380                         fprintf( fp, "-\n" );
381                 }
382                 break;
383
384         case LDAP_REQ_ADD:
385                 for ( a = op->ora_e->e_attrs ; a != NULL; a=a->a_next ) {
386                         if ( ri && ri->ri_attrs ) {
387                                 int is_in = ad_inlist( a->a_desc, ri->ri_attrs );
388                                 if ( ( !is_in && !ri->ri_exclude ) || ( is_in && ri->ri_exclude ) ) {
389                                         continue;
390                                 }
391
392                                 /* If the list includes objectClass names,
393                                  * only include those classes in the
394                                  * objectClass attribute
395                                  */
396                                 if ( ocs && a->a_desc == slap_schema.si_ad_objectClass ) {
397                                         int i;
398
399                                         if ( ocs == -1 ) ocs = 0;
400
401                                         for ( i=0; a->a_vals[i].bv_val; i++ ) {
402                                                 int match = 0;
403                                                 for ( an = ri->ri_attrs; an->an_name.bv_val; an++ ) {
404                                                         if ( an->an_oc ) {
405                                                                 ocs = 1;
406                                                                 match |= an->an_oc_exclude;
407                                                                 if ( a->a_vals[i].bv_len == an->an_name.bv_len
408                                                                         && !strcasecmp(a->a_vals[i].bv_val,
409                                                                                 an->an_name.bv_val ) ) {
410                                                                         match = !an->an_oc_exclude;
411                                                                         break;
412                                                                 }
413                                                         }
414                                                 }
415                                                 if ( !ocs ) break;
416
417                                                 match ^= ri->ri_exclude;
418                                                 if ( match ) {
419                                                         if ( dohdr ) {
420                                                                 rephdr( ri, op, fp );
421                                                                 fprintf( fp, "changetype: add\n" );
422                                                                 dohdr = 0;
423                                                         }
424                                                         vals[0] = an->an_name;
425                                                         print_vals( fp, &a->a_desc->ad_cname, vals );
426                                                 }
427                                         }
428                                         if ( ocs ) continue;
429                                 }
430                         }
431                         if ( dohdr ) {
432                                 rephdr( ri, op, fp );
433                                 fprintf( fp, "changetype: add\n" );
434                                 dohdr = 0;
435                         }
436                         print_vals( fp, &a->a_desc->ad_cname, a->a_vals );
437                 }
438                 break;
439
440         case LDAP_REQ_DELETE:
441                 rephdr( ri, op, fp );
442                 fprintf( fp, "changetype: delete\n" );
443                 break;
444
445         case LDAP_REQ_MODRDN:
446                 rephdr( ri, op, fp );
447                 fprintf( fp, "changetype: modrdn\n" );
448                 fprintf( fp, "newrdn: %s\n", op->orr_newrdn.bv_val );
449                 fprintf( fp, "deleteoldrdn: %d\n", op->orr_deleteoldrdn ? 1 : 0 );
450                 if( op->orr_newSup != NULL ) {
451                         fprintf( fp, "newsuperior: %s\n", op->orr_newSup->bv_val );
452                 }
453         }
454         fprintf( fp, "\n" );
455 }
456
457 static void
458 print_vals(
459         FILE *fp,
460         struct berval *type,
461         struct berval *bv )
462 {
463         ber_len_t i, len;
464         char    *buf, *bufp;
465
466         for ( i = 0, len = 0; bv && bv[i].bv_val; i++ ) {
467                 if ( bv[i].bv_len > len )
468                         len = bv[i].bv_len;
469         }
470
471         len = LDIF_SIZE_NEEDED( type->bv_len, len ) + 1;
472         buf = (char *) ch_malloc( len );
473
474         for ( ; bv && bv->bv_val; bv++ ) {
475                 bufp = buf;
476                 ldif_sput( &bufp, LDIF_PUT_VALUE, type->bv_val,
477                                     bv->bv_val, bv->bv_len );
478                 *bufp = '\0';
479
480                 fputs( buf, fp );
481
482         }
483         free( buf );
484 }