]> git.sur5r.net Git - openldap/blob - servers/slurpd/ri.c
Merge from LAMBERT branch
[openldap] / servers / slurpd / ri.c
1 /*
2  * Copyright (c) 1996 Regents of the University of Michigan.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of Michigan at Ann Arbor. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12
13 /*
14  * ri.c - routines used to manipulate Ri structures.  An Ri (Replica
15  * information) struct contains all information about one replica
16  * instance.  The Ri struct is defined in slurp.h
17  */
18
19
20
21 #include <stdio.h>
22 #include <signal.h>
23
24 #include "slurp.h"
25 #include "globals.h"
26
27
28 /* External references */
29 #ifdef NEEDPROTOS
30 extern void write_reject( Ri *, Re *, int, char * );
31 extern void do_nothing();
32 #else /* NEEDPROTOS */
33 extern void write_reject();
34 extern void do_nothing();
35 #endif /* NEEDPROTOS */
36
37 /* Forward references */
38 #ifdef NEEDPROTOS
39 static int ismine( Ri  *, Re  * );
40 static int isnew( Ri  *, Re  * );
41 void tsleep( time_t );
42 #else /* NEEDPROTOS */
43 static int ismine();
44 static int isnew();
45 void tsleep();
46 #endif /* NEEDPROTOS */
47
48
49 /*
50  * Process any unhandled replication entries in the queue.
51  */
52 static int
53 Ri_process(
54     Ri *ri
55 )
56 {
57     Rq          *rq = sglob->rq;
58     Re          *re, *new_re;
59     int         i;
60     int         rc ;
61     char        *errmsg;
62
63 #ifdef SIGSTKFLT
64     (void) SIGNAL( SIGSTKFLT, (void *) do_nothing );
65 #else
66     (void) SIGNAL( SIGUSR1, (void *) do_nothing );
67 #endif
68     (void) SIGNAL( SIGPIPE, SIG_IGN );
69     if ( ri == NULL ) {
70         Debug( LDAP_DEBUG_ANY, "Error: Ri_process: ri == NULL!\n", 0, 0, 0 );
71         return -1;
72     }
73
74     /*
75      * Startup code.  See if there's any work to do.  If not, wait on the
76      * rq->rq_more condition variable.
77      */
78     rq->rq_lock( rq );
79     while ( !sglob->slurpd_shutdown &&
80             (( re = rq->rq_gethead( rq )) == NULL )) {
81         /* No work - wait on condition variable */
82         pthread_cond_wait( &rq->rq_more, &rq->rq_mutex );
83     }
84
85     /*
86      * When we get here, there's work in the queue, and we have the
87      * queue locked.  re should be pointing to the head of the queue.
88      */
89     rq->rq_unlock( rq );
90     while ( !sglob->slurpd_shutdown ) {
91         if ( re != NULL ) {
92             if ( !ismine( ri, re )) {
93                 /* The Re doesn't list my host:port */
94                 Debug( LDAP_DEBUG_TRACE,
95                         "Replica %s:%d, skip repl record for %s (not mine)\n",
96                         ri->ri_hostname, ri->ri_port, re->re_dn );
97             } else if ( !isnew( ri, re )) {
98                 /* This Re is older than my saved status information */
99                 Debug( LDAP_DEBUG_TRACE,
100                         "Replica %s:%d, skip repl record for %s (old)\n",
101                         ri->ri_hostname, ri->ri_port, re->re_dn );
102             } else {
103                 rc = do_ldap( ri, re, &errmsg );
104                 switch ( rc ) {
105                 case DO_LDAP_ERR_RETRYABLE:
106                     tsleep( RETRY_SLEEP_TIME );
107                     Debug( LDAP_DEBUG_ANY,
108                             "Retrying operation for DN %s on replica %s:%d\n",
109                             re->re_dn, ri->ri_hostname, ri->ri_port );
110                     continue;
111                     break;
112                 case DO_LDAP_ERR_FATAL:
113                     /* Non-retryable error.  Write rejection log. */
114                     write_reject( ri, re, ri->ri_ldp->ld_errno, errmsg );
115                     /* Update status ... */
116                     (void) sglob->st->st_update( sglob->st, ri->ri_stel, re );
117                     /* ... and write to disk */
118                     (void) sglob->st->st_write( sglob->st );
119                     break;
120                 default:
121                     /* LDAP op completed ok - update status... */
122                     (void) sglob->st->st_update( sglob->st, ri->ri_stel, re );
123                     /* ... and write to disk */
124                     (void) sglob->st->st_write( sglob->st );
125                     break;
126                 }
127             }
128         } else {
129             Debug( LDAP_DEBUG_ANY, "Error: re is null in Ri_process\n",
130                     0, 0, 0 );
131         }
132         rq->rq_lock( rq );
133         while ( !sglob->slurpd_shutdown &&
134                 ((new_re = re->re_getnext( re )) == NULL )) {
135             if ( sglob->one_shot_mode ) {
136                 return 0;
137             }
138             /* No work - wait on condition variable */
139             pthread_cond_wait( &rq->rq_more, &rq->rq_mutex );
140         }
141         re->re_decrefcnt( re );
142         re = new_re;
143         rq->rq_unlock( rq );
144         if ( sglob->slurpd_shutdown ) {
145             return 0;
146         }
147     }
148     return 0;
149 }
150
151
152 /*
153  * Wake a replication thread which may be sleeping.
154  * Send it a SIG(STKFLT|USR1).
155  */
156 static void
157 Ri_wake(
158     Ri *ri
159
160 {
161     if ( ri == NULL ) {
162         return;
163     }
164 #ifdef SIGSTKFLT
165     pthread_kill( ri->ri_tid, SIGSTKFLT );
166     (void) SIGNAL( SIGSTKFLT, (void *) do_nothing );
167 #else
168     pthread_kill( ri->ri_tid, SIGUSR1 );
169     (void) SIGNAL( SIGUSR1, (void *) do_nothing );
170 #endif
171 }
172
173
174
175 /* 
176  * Allocate and initialize an Ri struct.
177  */
178 int
179 Ri_init(
180     Ri  **ri
181 )
182 {
183     (*ri) = ( Ri * ) malloc( sizeof( Ri ));
184     if ( *ri == NULL ) {
185         return -1;
186     }
187
188     /* Initialize member functions */
189     (*ri)->ri_process = Ri_process;
190     (*ri)->ri_wake = Ri_wake;
191
192     /* Initialize private data */
193     (*ri)->ri_hostname = NULL;
194     (*ri)->ri_port = 0;
195     (*ri)->ri_ldp = NULL;
196     (*ri)->ri_bind_method = 0;
197     (*ri)->ri_bind_dn = NULL;
198     (*ri)->ri_password = NULL;
199     (*ri)->ri_principal = NULL;
200     (*ri)->ri_srvtab = NULL;
201     (*ri)->ri_curr = NULL;
202
203     return 0;
204 }
205
206
207
208
209 /*
210  * Return 1 if the hostname and port in re match the hostname and port
211  * in ri, otherwise return zero.
212  */
213 static int
214 ismine(
215     Ri  *ri,
216     Re  *re
217 )
218 {
219     Rh  *rh;
220     int i;
221
222     if ( ri == NULL || re == NULL || ri->ri_hostname == NULL ||
223             re->re_replicas == NULL ) {
224         return 0;
225     }
226     rh = re->re_replicas;
227     for ( i = 0; rh[ i ].rh_hostname != NULL; i++ ) {
228         if ( !strcmp( rh[ i ].rh_hostname, ri->ri_hostname) &&
229                 rh[ i ].rh_port == ri->ri_port ) {
230             return 1;
231         }
232     }
233     return 0;
234 }
235
236
237
238
239 /*
240  * Return 1 if the Re's timestamp/seq combination are greater than the
241  * timestamp and seq in the Ri's ri_stel member.  In other words, if we
242  * find replication entries in the log which we've already processed,
243  * don't process them.  If the re is "old," return 0.
244  * No check for NULL pointers is done.
245  */
246 static int
247 isnew(
248     Ri  *ri,
249     Re  *re
250 )
251 {
252     int x;
253     int ret;
254
255     /* Lock the St struct to avoid a race */
256     sglob->st->st_lock( sglob->st );
257     x = strcmp( re->re_timestamp, ri->ri_stel->last );
258     if ( x > 0 ) {
259         /* re timestamp is newer */
260         ret = 1;
261     } else if ( x < 0 ) {
262         ret = 0;
263     } else {
264         /* timestamps were equal */
265         if ( re->re_seq > ri->ri_stel->seq ) {
266             /* re seq is newer */
267             ret = 1;
268         } else {
269             ret = 0;
270         }
271     }
272     sglob->st->st_unlock( sglob->st );
273     return ret;
274 }
275
276