]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/dbcache.c
ea3c3610c96f0f22d2fece825d06b9b580644f53
[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         sprintf( buf, "%s" LDAP_DIRSEP "%s%s",
38                 li->li_directory, name, suffix );
39
40         if( li->li_dblocking ) {
41                 flags |= LDBM_LOCKING;
42         } else {
43                 flags |= LDBM_NOLOCKING;
44         }
45         
46         if( li->li_dbwritesync ) {
47                 flags |= LDBM_SYNC;
48         } else {
49                 flags |= LDBM_NOSYNC;
50         }
51         
52         Debug( LDAP_DEBUG_TRACE, "=> ldbm_cache_open( \"%s\", %d, %o )\n", buf,
53             flags, li->li_mode );
54
55         curtime = slap_get_time();
56         empty = MAXDBCACHE;
57
58         ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
59         do {
60                 lru = 0;
61                 oldtime = curtime;
62                 for ( i = 0; i < MAXDBCACHE; i++ ) {
63                         /* see if this slot is free */
64                         if ( li->li_dbcache[i].dbc_name == NULL) {
65                                 empty = i;
66                                 continue;
67                         }
68
69                         if ( strcmp( li->li_dbcache[i].dbc_name, buf ) == 0 ) {
70                                 /* already open - return it */
71                                 if (li->li_dbcache[i].dbc_flags != flags
72                                         && li->li_dbcache[i].dbc_refcnt == 0)
73                                 {
74                                         /* we don't want to use an open cache with different
75                                          * permissions (esp. if we need write but the open
76                                          * cache is read-only).  So close this one if
77                                          * possible, and re-open below.
78                                          *
79                                          * FIXME:  what about the case where the refcount
80                                          * is > 0?  right now, we're using it anyway and
81                                          * just praying.  Can there be more than one open
82                                          * cache to the same db?
83                                          *
84                                          * Also, it's really only necessary to compare the
85                                          * read-only flag, instead of all of the flags,
86                                          * but for now I'm checking all of them.
87                                          */
88                                         lru = i;
89                                         empty = MAXDBCACHE;
90                                         break;
91                                 }
92                                 li->li_dbcache[i].dbc_refcnt++;
93                                 Debug( LDAP_DEBUG_TRACE,
94                                     "<= ldbm_cache_open (cache %d)\n", i, 0, 0 );
95                                 ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
96                                 return( &li->li_dbcache[i] );
97                         }
98
99                         /* keep track of lru db */
100                         if ( li->li_dbcache[i].dbc_lastref < oldtime
101                                 && li->li_dbcache[i].dbc_refcnt == 0 )
102                         {
103                                 lru = i;
104                                 oldtime = li->li_dbcache[i].dbc_lastref;
105                         }
106                 }
107
108                 i = empty;
109                 if ( i == MAXDBCACHE ) {
110                         /* no empty slots, not already open - close lru and use that slot */
111                         if ( li->li_dbcache[lru].dbc_refcnt == 0 ) {
112                                 i = lru;
113                                 ldbm_close( li->li_dbcache[i].dbc_db );
114                                 free( li->li_dbcache[i].dbc_name );
115                                 li->li_dbcache[i].dbc_name = NULL;
116                         } else {
117                                 Debug( LDAP_DEBUG_ANY,
118                                     "ldbm_cache_open no unused db to close - waiting\n",
119                                     0, 0, 0 );
120                                 ldap_pvt_thread_cond_wait( &li->li_dbcache_cv,
121                                             &li->li_dbcache_mutex );
122                                 /* after waiting for a free slot, go back to square
123                                  * one: look for an open cache for this db, or an
124                                  * empty slot, or an unref'ed cache, or wait again.
125                                  */
126                         }
127                 }
128         } while (i == MAXDBCACHE);
129
130         if ( (li->li_dbcache[i].dbc_db = ldbm_open( buf, flags, li->li_mode,
131             li->li_dbcachesize )) == NULL )
132         {
133                 int err = errno;
134                 Debug( LDAP_DEBUG_TRACE,
135                     "<= ldbm_cache_open NULL \"%s\" errno=%d reason=\"%s\")\n",
136                     buf, err, err > -1 && err < sys_nerr ?
137                     sys_errlist[err] : "unknown" );
138                 ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
139                 return( NULL );
140         }
141         li->li_dbcache[i].dbc_name = ch_strdup( buf );
142         li->li_dbcache[i].dbc_refcnt = 1;
143         li->li_dbcache[i].dbc_lastref = curtime;
144         li->li_dbcache[i].dbc_flags = flags;
145         li->li_dbcache[i].dbc_dirty = 0;
146 #ifdef HAVE_ST_BLKSIZE
147         if ( stat( buf, &st ) == 0 ) {
148                 li->li_dbcache[i].dbc_blksize = st.st_blksize;
149         } else
150 #endif
151         {
152                 li->li_dbcache[i].dbc_blksize = DEFAULT_BLOCKSIZE;
153         }
154         li->li_dbcache[i].dbc_maxids = (li->li_dbcache[i].dbc_blksize /
155             sizeof(ID)) - ID_BLOCK_IDS_OFFSET;
156         li->li_dbcache[i].dbc_maxindirect = ( SLAPD_LDBM_MIN_MAXIDS /
157             li->li_dbcache[i].dbc_maxids ) + 1;
158
159         assert( li->li_dbcache[i].dbc_maxindirect < 256 );
160
161         Debug( LDAP_DEBUG_ARGS,
162             "ldbm_cache_open (blksize %ld) (maxids %d) (maxindirect %d)\n",
163             li->li_dbcache[i].dbc_blksize, li->li_dbcache[i].dbc_maxids,
164             li->li_dbcache[i].dbc_maxindirect );
165         Debug( LDAP_DEBUG_TRACE, "<= ldbm_cache_open (opened %d)\n", i, 0, 0 );
166         ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
167         return( &li->li_dbcache[i] );
168 }
169
170 void
171 ldbm_cache_close( Backend *be, DBCache *db )
172 {
173         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
174
175         if( li->li_dbwritesync && db->dbc_dirty ) {
176                 ldbm_sync( db->dbc_db );
177                 db->dbc_dirty = 0;
178         }
179
180         ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
181         if ( --db->dbc_refcnt <= 0 ) {
182                 db->dbc_refcnt = 0;
183                 ldap_pvt_thread_cond_signal( &li->li_dbcache_cv );
184         }
185         ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
186 }
187
188 void
189 ldbm_cache_really_close( Backend *be, DBCache *db )
190 {
191         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
192
193         ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
194         if ( --db->dbc_refcnt <= 0 ) {
195                 db->dbc_refcnt = 0;
196                 ldap_pvt_thread_cond_signal( &li->li_dbcache_cv );
197                 ldbm_close( db->dbc_db );
198                 free( db->dbc_name );
199                 db->dbc_name = NULL;
200         }
201         ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
202 }
203
204 void
205 ldbm_cache_flush_all( Backend *be )
206 {
207         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
208         int             i;
209
210         ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
211         for ( i = 0; i < MAXDBCACHE; i++ ) {
212                 if ( li->li_dbcache[i].dbc_name != NULL ) {
213                         Debug( LDAP_DEBUG_TRACE, "ldbm flushing db (%s)\n",
214                             li->li_dbcache[i].dbc_name, 0, 0 );
215                         ldbm_sync( li->li_dbcache[i].dbc_db );
216                         li->li_dbcache[i].dbc_dirty = 0;
217                         if ( li->li_dbcache[i].dbc_refcnt != 0 ) {
218                                 Debug( LDAP_DEBUG_TRACE,
219                                        "refcnt = %d, couldn't close db (%s)\n",
220                                        li->li_dbcache[i].dbc_refcnt,
221                                        li->li_dbcache[i].dbc_name, 0 );
222                         } else {
223                                 Debug( LDAP_DEBUG_TRACE,
224                                        "ldbm closing db (%s)\n",
225                                        li->li_dbcache[i].dbc_name, 0, 0 );
226                                 ldap_pvt_thread_cond_signal( &li->li_dbcache_cv );
227                                 ldbm_close( li->li_dbcache[i].dbc_db );
228                                 free( li->li_dbcache[i].dbc_name );
229                                 li->li_dbcache[i].dbc_name = NULL;
230                         }
231                 }
232         }
233         ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
234 }
235
236 Datum
237 ldbm_cache_fetch(
238     DBCache     *db,
239     Datum               key
240 )
241 {
242         Datum   data;
243
244         return ldbm_fetch( db->dbc_db, key );
245
246         return( data );
247 }
248
249 int
250 ldbm_cache_store(
251     DBCache     *db,
252     Datum               key,
253     Datum               data,
254     int                 flags
255 )
256 {
257         int     rc;
258
259 #ifdef LDBM_DEBUG
260         Statslog( LDAP_DEBUG_STATS,
261                 "=> ldbm_cache_store(): key.dptr=%s, key.dsize=%d\n",
262                 key.dptr, key.dsize, 0, 0, 0 );
263
264         Statslog( LDAP_DEBUG_STATS,
265                 "=> ldbm_cache_store(): key.dptr=0x%08x, data.dptr=0x%0 8x\n",
266                 key.dptr, data.dptr, 0, 0, 0 );
267
268         Statslog( LDAP_DEBUG_STATS,
269                 "=> ldbm_cache_store(): data.dptr=%s, data.dsize=%d\n",
270                 data.dptr, data.dsize, 0, 0, 0 );
271
272         Statslog( LDAP_DEBUG_STATS,
273                 "=> ldbm_cache_store(): flags=0x%08x\n",
274                 flags, 0, 0, 0, 0 );
275 #endif /* LDBM_DEBUG */
276
277         db->dbc_dirty = 1;
278         rc = ldbm_store( db->dbc_db, key, data, flags );
279
280         return( rc );
281 }
282
283 int
284 ldbm_cache_delete(
285     DBCache     *db,
286     Datum               key
287 )
288 {
289         int     rc;
290
291         db->dbc_dirty = 1;
292         rc = ldbm_delete( db->dbc_db, key );
293
294         return( rc );
295 }