]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/dbcache.c
Add sync_daemon to daemon.c, enabled by global configuration
[openldap] / servers / slapd / back-ldbm / dbcache.c
1 /* ldbmcache.c - maintain a cache of open ldbm files */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/errno.h>
13 #include <ac/socket.h>
14 #include <ac/string.h>
15 #include <ac/time.h>
16 #include <sys/stat.h>
17
18 #include "slap.h"
19 #include "back-ldbm.h"
20
21 DBCache *
22 ldbm_cache_open(
23     Backend     *be,
24     const char  *name,
25     const char  *suffix,
26     int         flags
27 )
28 {
29         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
30         int             i, lru, empty;
31         time_t          oldtime, curtime;
32         char            buf[MAXPATHLEN];
33 #ifdef HAVE_ST_BLKSIZE
34         struct stat     st;
35 #endif
36
37         if (li->li_envdirok)
38                 sprintf( buf, "%s%s", name, suffix );
39         else
40                 sprintf( buf, "%s" LDAP_DIRSEP "%s%s",
41                         li->li_directory, name, suffix );
42
43         if( li->li_dblocking ) {
44                 flags |= LDBM_LOCKING;
45         } else {
46                 flags |= LDBM_NOLOCKING;
47         }
48         
49         if( li->li_dbwritesync && global_backendsyncfreq == 0) {
50                 flags |= LDBM_SYNC;
51         } else {
52                 flags |= LDBM_NOSYNC;
53         }
54         
55 #ifdef NEW_LOGGING
56         LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
57                    "ldbm_cache_open: \"%s\", %d, %o\n", buf, flags, li->li_mode ));
58 #else
59         Debug( LDAP_DEBUG_TRACE, "=> ldbm_cache_open( \"%s\", %d, %o )\n", buf,
60             flags, li->li_mode );
61 #endif
62
63
64         curtime = slap_get_time();
65         empty = MAXDBCACHE;
66
67         ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
68         do {
69                 lru = 0;
70                 oldtime = curtime;
71                 for ( i = 0; i < MAXDBCACHE; i++ ) {
72                         /* see if this slot is free */
73                         if ( li->li_dbcache[i].dbc_name == NULL) {
74                                 if (empty == MAXDBCACHE)
75                                         empty = i;
76                                 continue;
77                         }
78
79                         if ( strcmp( li->li_dbcache[i].dbc_name, buf ) == 0 ) {
80                                 /* already open - return it */
81                                 if (li->li_dbcache[i].dbc_flags != flags
82                                         && li->li_dbcache[i].dbc_refcnt == 0)
83                                 {
84                                         /* we don't want to use an open cache with different
85                                          * permissions (esp. if we need write but the open
86                                          * cache is read-only).  So close this one if
87                                          * possible, and re-open below.
88                                          *
89                                          * FIXME:  what about the case where the refcount
90                                          * is > 0?  right now, we're using it anyway and
91                                          * just praying.  Can there be more than one open
92                                          * cache to the same db?
93                                          *
94                                          * Also, it's really only necessary to compare the
95                                          * read-only flag, instead of all of the flags,
96                                          * but for now I'm checking all of them.
97                                          */
98                                         lru = i;
99                                         empty = MAXDBCACHE;
100                                         break;
101                                 }
102                                 li->li_dbcache[i].dbc_refcnt++;
103 #ifdef NEW_LOGGING
104                                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
105                                            "ldbm_cache_open: cache %d\n", i ));
106 #else
107                                 Debug( LDAP_DEBUG_TRACE,
108                                     "<= ldbm_cache_open (cache %d)\n", i, 0, 0 );
109 #endif
110
111                                 ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
112                                 return( &li->li_dbcache[i] );
113                         }
114
115                         /* keep track of lru db */
116                         if ( li->li_dbcache[i].dbc_lastref < oldtime
117                                 && li->li_dbcache[i].dbc_refcnt == 0 )
118                         {
119                                 lru = i;
120                                 oldtime = li->li_dbcache[i].dbc_lastref;
121                         }
122                 }
123
124                 i = empty;
125                 if ( i == MAXDBCACHE ) {
126                         /* no empty slots, not already open - close lru and use that slot */
127                         if ( li->li_dbcache[lru].dbc_refcnt == 0 ) {
128                                 i = lru;
129                                 ldbm_close( li->li_dbcache[i].dbc_db );
130                                 free( li->li_dbcache[i].dbc_name );
131                                 li->li_dbcache[i].dbc_name = NULL;
132                         } else {
133 #ifdef NEW_LOGGING
134                                 LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
135                                            "ldbm_cache_open: no unused db to close - waiting\n" ));
136 #else
137                                 Debug( LDAP_DEBUG_ANY,
138                                     "ldbm_cache_open no unused db to close - waiting\n",
139                                     0, 0, 0 );
140 #endif
141
142                                 ldap_pvt_thread_cond_wait( &li->li_dbcache_cv,
143                                             &li->li_dbcache_mutex );
144                                 /* after waiting for a free slot, go back to square
145                                  * one: look for an open cache for this db, or an
146                                  * empty slot, or an unref'ed cache, or wait again.
147                                  */
148                         }
149                 }
150         } while (i == MAXDBCACHE);
151
152         if ( (li->li_dbcache[i].dbc_db = ldbm_open( li->li_dbenv, buf, flags, li->li_mode,
153             li->li_dbcachesize )) == NULL )
154         {
155                 int err = errno;
156 #ifdef NEW_LOGGING
157                 LDAP_LOG(( "cache", LDAP_LEVEL_ERR,
158                            "ldbm_cache_open: \"%s\" failed, errono=%d, reason=%s\n",
159                            buf, err, err > -1 && err < sys_nerr ? sys_errlist[err] :
160                            "unknown" ));
161 #else
162                 Debug( LDAP_DEBUG_TRACE,
163                     "<= ldbm_cache_open NULL \"%s\" errno=%d reason=\"%s\")\n",
164                     buf, err, err > -1 && err < sys_nerr ?
165                     sys_errlist[err] : "unknown" );
166 #endif
167
168                 ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
169                 return( NULL );
170         }
171         li->li_dbcache[i].dbc_name = ch_strdup( buf );
172         li->li_dbcache[i].dbc_refcnt = 1;
173         li->li_dbcache[i].dbc_lastref = curtime;
174         li->li_dbcache[i].dbc_flags = flags;
175         li->li_dbcache[i].dbc_dirty = 0;
176 #ifdef HAVE_ST_BLKSIZE
177         if ( stat( buf, &st ) == 0 ) {
178                 li->li_dbcache[i].dbc_blksize = st.st_blksize;
179         } else
180 #endif
181         {
182                 li->li_dbcache[i].dbc_blksize = DEFAULT_BLOCKSIZE;
183         }
184         li->li_dbcache[i].dbc_maxids = (li->li_dbcache[i].dbc_blksize /
185             sizeof(ID)) - ID_BLOCK_IDS_OFFSET;
186         li->li_dbcache[i].dbc_maxindirect = ( SLAPD_LDBM_MIN_MAXIDS /
187             li->li_dbcache[i].dbc_maxids ) + 1;
188
189         assert( li->li_dbcache[i].dbc_maxindirect < 256 );
190
191 #ifdef NEW_LOGGING
192         LDAP_LOG(( "cache", LDAP_LEVEL_ARGS,
193                    "ldbm_cache_open: blksize:%ld  maxids:%d  maxindirect:%d\n",
194                    li->li_dbcache[i].dbc_blksize, li->li_dbcache[i].dbc_maxids,
195                    li->li_dbcache[i].dbc_maxindirect ));
196 #else
197         Debug( LDAP_DEBUG_ARGS,
198             "ldbm_cache_open (blksize %ld) (maxids %d) (maxindirect %d)\n",
199             li->li_dbcache[i].dbc_blksize, li->li_dbcache[i].dbc_maxids,
200             li->li_dbcache[i].dbc_maxindirect );
201 #endif
202
203 #ifdef NEW_LOGGING
204         LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
205                    "ldbm_cache_open: opened %d\n", i ));
206 #else
207         Debug( LDAP_DEBUG_TRACE, "<= ldbm_cache_open (opened %d)\n", i, 0, 0 );
208 #endif
209
210         ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
211         return( &li->li_dbcache[i] );
212 }
213
214 void
215 ldbm_cache_close( Backend *be, DBCache *db )
216 {
217         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
218
219         if( li->li_dbwritesync && db->dbc_dirty ) {
220                 ldbm_sync( db->dbc_db );
221                 db->dbc_dirty = 0;
222         }
223
224         ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
225         if ( --db->dbc_refcnt <= 0 ) {
226                 db->dbc_refcnt = 0;
227                 ldap_pvt_thread_cond_signal( &li->li_dbcache_cv );
228         }
229         ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
230 }
231
232 void
233 ldbm_cache_really_close( Backend *be, DBCache *db )
234 {
235         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
236
237         ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
238         if ( --db->dbc_refcnt <= 0 ) {
239                 db->dbc_refcnt = 0;
240                 ldap_pvt_thread_cond_signal( &li->li_dbcache_cv );
241                 ldbm_close( db->dbc_db );
242                 free( db->dbc_name );
243                 db->dbc_name = NULL;
244         }
245         ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
246 }
247
248 void
249 ldbm_cache_flush_all( Backend *be )
250 {
251         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
252         int             i;
253
254         ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
255         for ( i = 0; i < MAXDBCACHE; i++ ) {
256                 if ( li->li_dbcache[i].dbc_name != NULL ) {
257 #ifdef NEW_LOGGING
258                         LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
259                                    "ldbm_cache_flush_all: flushing db (%s)\n",
260                                    li->li_dbcache[i].dbc_name ));
261 #else
262                         Debug( LDAP_DEBUG_TRACE, "ldbm flushing db (%s)\n",
263                             li->li_dbcache[i].dbc_name, 0, 0 );
264 #endif
265
266                         ldbm_sync( li->li_dbcache[i].dbc_db );
267                         li->li_dbcache[i].dbc_dirty = 0;
268                         if ( li->li_dbcache[i].dbc_refcnt != 0 ) {
269 #ifdef NEW_LOGGING
270                                 LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
271                                            "ldbm_cache_flush_all: couldn't close db (%s), refcnt=%d\n",
272                                            li->li_dbcache[i].dbc_name, li->li_dbcache[i].dbc_refcnt ));
273 #else
274                                 Debug( LDAP_DEBUG_TRACE,
275                                        "refcnt = %d, couldn't close db (%s)\n",
276                                        li->li_dbcache[i].dbc_refcnt,
277                                        li->li_dbcache[i].dbc_name, 0 );
278 #endif
279
280                         } else {
281 #ifdef NEW_LOGGING
282                                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
283                                            "ldbm_cache_flush_all: ldbm closing db (%s)\n",
284                                            li->li_dbcache[i].dbc_name ));
285 #else
286                                 Debug( LDAP_DEBUG_TRACE,
287                                        "ldbm closing db (%s)\n",
288                                        li->li_dbcache[i].dbc_name, 0, 0 );
289 #endif
290
291                                 ldap_pvt_thread_cond_signal( &li->li_dbcache_cv );
292                                 ldbm_close( li->li_dbcache[i].dbc_db );
293                                 free( li->li_dbcache[i].dbc_name );
294                                 li->li_dbcache[i].dbc_name = NULL;
295                         }
296                 }
297         }
298         ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
299 }
300
301 void
302 ldbm_cache_sync( Backend *be )
303 {
304         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
305         int             i;
306
307         ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
308         for ( i = 0; i < MAXDBCACHE; i++ ) {
309                 if ( li->li_dbcache[i].dbc_name != NULL && li->li_dbcache[i].dbc_dirty ) {
310                         Debug(  LDAP_DEBUG_TRACE, "ldbm syncing db (%s)\n",
311                                 li->li_dbcache[i].dbc_name, 0, 0 );
312                         ldbm_sync( li->li_dbcache[i].dbc_db );
313                         li->li_dbcache[i].dbc_dirty = 0;
314                 }
315         }
316         ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
317 }
318
319 Datum
320 ldbm_cache_fetch(
321     DBCache     *db,
322     Datum               key
323 )
324 {
325         Datum   data;
326
327         return ldbm_fetch( db->dbc_db, key );
328
329         return( data );
330 }
331
332 int
333 ldbm_cache_store(
334     DBCache     *db,
335     Datum               key,
336     Datum               data,
337     int                 flags
338 )
339 {
340         int     rc;
341
342 #ifdef LDBM_DEBUG
343         Statslog( LDAP_DEBUG_STATS,
344                 "=> ldbm_cache_store(): key.dptr=%s, key.dsize=%d\n",
345                 key.dptr, key.dsize, 0, 0, 0 );
346
347         Statslog( LDAP_DEBUG_STATS,
348                 "=> ldbm_cache_store(): key.dptr=0x%08x, data.dptr=0x%0 8x\n",
349                 key.dptr, data.dptr, 0, 0, 0 );
350
351         Statslog( LDAP_DEBUG_STATS,
352                 "=> ldbm_cache_store(): data.dptr=%s, data.dsize=%d\n",
353                 data.dptr, data.dsize, 0, 0, 0 );
354
355         Statslog( LDAP_DEBUG_STATS,
356                 "=> ldbm_cache_store(): flags=0x%08x\n",
357                 flags, 0, 0, 0, 0 );
358 #endif /* LDBM_DEBUG */
359
360         db->dbc_dirty = 1;
361         rc = ldbm_store( db->dbc_db, key, data, flags );
362
363         return( rc );
364 }
365
366 int
367 ldbm_cache_delete(
368     DBCache     *db,
369     Datum               key
370 )
371 {
372         int     rc;
373
374         db->dbc_dirty = 1;
375         rc = ldbm_delete( db->dbc_db, key );
376
377         return( rc );
378 }