]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/dbcache.c
ff09593f930dd593c68797b12e8dd1da03c9b585
[openldap] / servers / slapd / back-ldbm / dbcache.c
1 /* ldbmcache.c - maintain a cache of open ldbm files */
2
3 #include "portable.h"
4
5 #include <stdio.h>
6
7 #include <ac/errno.h>
8 #include <ac/socket.h>
9 #include <ac/string.h>
10 #include <ac/time.h>
11
12 #include <sys/stat.h>
13
14 #ifdef HAVE_SYS_PARAM_H
15 #include <sys/param.h>
16 #endif
17
18 #include "slap.h"
19 #include "back-ldbm.h"
20 #include "ldapconfig.h"
21
22 #ifdef DECL_SYS_ERRLIST
23 extern int              sys_nerr;
24 extern char             *sys_errlist[];
25 #endif
26
27 extern time_t           currenttime;
28 extern pthread_mutex_t  currenttime_mutex;
29
30 struct dbcache *
31 ldbm_cache_open(
32     Backend     *be,
33     char        *name,
34     char        *suffix,
35     int         flags
36 )
37 {
38         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
39         int             i, lru;
40         time_t          oldtime, curtime;
41         char            buf[MAXPATHLEN];
42         LDBM            db;
43         struct stat     st;
44
45         sprintf( buf, "%s/%s%s", li->li_directory, name, suffix );
46
47         Debug( LDAP_DEBUG_TRACE, "=> ldbm_cache_open( \"%s\", %d, %o )\n", buf,
48             flags, li->li_mode );
49
50         lru = 0;
51         pthread_mutex_lock( &currenttime_mutex );
52         curtime = currenttime;
53         pthread_mutex_unlock( &currenttime_mutex );
54         oldtime = curtime;
55
56         pthread_mutex_lock( &li->li_dbcache_mutex );
57         for ( i = 0; i < MAXDBCACHE && li->li_dbcache[i].dbc_name != NULL;
58             i++ ) {
59                 /* already open - return it */
60                 if ( strcmp( li->li_dbcache[i].dbc_name, buf ) == 0 ) {
61                         li->li_dbcache[i].dbc_refcnt++;
62                         Debug( LDAP_DEBUG_TRACE,
63                             "<= ldbm_cache_open (cache %d)\n", i, 0, 0 );
64                         pthread_mutex_unlock( &li->li_dbcache_mutex );
65                         return( &li->li_dbcache[i] );
66                 }
67
68                 /* keep track of lru db */
69                 if ( li->li_dbcache[i].dbc_lastref < oldtime &&
70                     li->li_dbcache[i].dbc_refcnt == 0 ) {
71                         lru = i;
72                         oldtime = li->li_dbcache[i].dbc_lastref;
73                 }
74         }
75
76         /* no empty slots, not already open - close lru and use that slot */
77         if ( i == MAXDBCACHE ) {
78                 i = lru;
79                 if ( li->li_dbcache[i].dbc_refcnt != 0 ) {
80                         Debug( LDAP_DEBUG_ANY,
81                             "ldbm_cache_open no unused db to close - waiting\n",
82                             0, 0, 0 );
83                         lru = -1;
84                         while ( lru == -1 ) {
85                                 pthread_cond_wait( &li->li_dbcache_cv,
86                                     &li->li_dbcache_mutex );
87                                 for ( i = 0; i < MAXDBCACHE; i++ ) {
88                                         if ( li->li_dbcache[i].dbc_refcnt
89                                             == 0 ) {
90                                                 lru = i;
91                                                 break;
92                                         }
93                                 }
94                         }
95                         i = lru;
96                 }
97                 ldbm_close( li->li_dbcache[i].dbc_db );
98                 free( li->li_dbcache[i].dbc_name );
99                 li->li_dbcache[i].dbc_name = NULL;
100         }
101
102         if ( (li->li_dbcache[i].dbc_db = ldbm_open( buf, flags, li->li_mode,
103             li->li_dbcachesize )) == NULL ) {
104                 Debug( LDAP_DEBUG_TRACE,
105                     "<= ldbm_cache_open NULL \"%s\" errno %d reason \"%s\")\n",
106                     buf, errno, errno > -1 && errno < sys_nerr ?
107                     sys_errlist[errno] : "unknown" );
108                 pthread_mutex_unlock( &li->li_dbcache_mutex );
109                 return( NULL );
110         }
111         li->li_dbcache[i].dbc_name = strdup( buf );
112         li->li_dbcache[i].dbc_refcnt = 1;
113         li->li_dbcache[i].dbc_lastref = curtime;
114         if ( stat( buf, &st ) == 0 ) {
115                 li->li_dbcache[i].dbc_blksize = st.st_blksize;
116         } else {
117                 li->li_dbcache[i].dbc_blksize = DEFAULT_BLOCKSIZE;
118         }
119         li->li_dbcache[i].dbc_maxids = (li->li_dbcache[i].dbc_blksize /
120             sizeof(ID)) - 2;
121         li->li_dbcache[i].dbc_maxindirect = (SLAPD_LDBM_MIN_MAXIDS /
122             li->li_dbcache[i].dbc_maxids) + 1;
123
124         Debug( LDAP_DEBUG_ARGS,
125             "ldbm_cache_open (blksize %d) (maxids %d) (maxindirect %d)\n",
126             li->li_dbcache[i].dbc_blksize, li->li_dbcache[i].dbc_maxids,
127             li->li_dbcache[i].dbc_maxindirect );
128         Debug( LDAP_DEBUG_TRACE, "<= ldbm_cache_open (opened %d)\n", i, 0, 0 );
129         pthread_mutex_unlock( &li->li_dbcache_mutex );
130         return( &li->li_dbcache[i] );
131 }
132
133 void
134 ldbm_cache_close( Backend *be, struct dbcache *db )
135 {
136         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
137
138         pthread_mutex_lock( &li->li_dbcache_mutex );
139         if ( --db->dbc_refcnt == 0 ) {
140                 pthread_cond_signal( &li->li_dbcache_cv );
141         }
142         pthread_mutex_unlock( &li->li_dbcache_mutex );
143 }
144
145 void
146 ldbm_cache_really_close( Backend *be, struct dbcache *db )
147 {
148         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
149
150         pthread_mutex_lock( &li->li_dbcache_mutex );
151         if ( --db->dbc_refcnt == 0 ) {
152                 pthread_cond_signal( &li->li_dbcache_cv );
153                 ldbm_close( db->dbc_db );
154                 free( db->dbc_name );
155                 db->dbc_name = NULL;
156         }
157         pthread_mutex_unlock( &li->li_dbcache_mutex );
158 }
159
160 void
161 ldbm_cache_flush_all( Backend *be )
162 {
163         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
164         int             i;
165
166         pthread_mutex_lock( &li->li_dbcache_mutex );
167         for ( i = 0; i < MAXDBCACHE; i++ ) {
168                 if ( li->li_dbcache[i].dbc_name != NULL ) {
169                         Debug( LDAP_DEBUG_TRACE, "ldbm flushing db (%s)\n",
170                             li->li_dbcache[i].dbc_name, 0, 0 );
171                         pthread_mutex_lock( &li->li_dbcache[i].dbc_mutex );
172                         ldbm_sync( li->li_dbcache[i].dbc_db );
173                         pthread_mutex_unlock( &li->li_dbcache[i].dbc_mutex );
174                 }
175         }
176         pthread_mutex_unlock( &li->li_dbcache_mutex );
177 }
178
179 Datum
180 ldbm_cache_fetch(
181     struct dbcache      *db,
182     Datum               key
183 )
184 {
185         Datum   data;
186 #ifdef HAVE_BERKELEY_DB2
187         memset( &data, 0, sizeof( data ) );
188 #endif
189
190         pthread_mutex_lock( &db->dbc_mutex );
191 #ifdef reentrant_database
192         /* increment reader count */
193         db->dbc_readers++
194         pthread_mutex_unlock( &db->dbc_mutex );
195 #endif
196
197         data = ldbm_fetch( db->dbc_db, key );
198
199 #ifdef reentrant_database
200         pthread_mutex_lock( &db->dbc_mutex );
201         /* decrement reader count & signal any waiting writers */
202         if ( --db->dbc_readers == 0 ) {
203                 pthread_cond_signal( &db->dbc_cv );
204         }
205 #endif
206         pthread_mutex_unlock( &db->dbc_mutex );
207
208         return( data );
209 }
210
211 int
212 ldbm_cache_store(
213     struct dbcache      *db,
214     Datum               key,
215     Datum               data,
216     int                 flags
217 )
218 {
219         int     rc;
220
221         pthread_mutex_lock( &db->dbc_mutex );
222 #ifdef reentrant_database
223         /* wait for reader count to drop to zero */
224         while ( db->dbc_readers > 0 ) {
225                 pthread_cond_wait( &db->dbc_cv, &db->dbc_mutex );
226         }
227 #endif
228
229 #ifdef LDBM_DEBUG
230         Statslog( LDAP_DEBUG_STATS,
231                 "=> ldbm_cache_store(): key.dptr=%s, key.dsize=%d\n",
232                 key.dptr, key.dsize, 0, 0, 0 );
233
234         Statslog( LDAP_DEBUG_STATS,
235                 "=> ldbm_cache_store(): key.dptr=0x%08x, data.dptr=0x%0 8x\n",
236                 key.dptr, data.dptr, 0, 0, 0 );
237
238         Statslog( LDAP_DEBUG_STATS,
239                 "=> ldbm_cache_store(): data.dptr=%s, data.dsize=%d\n",
240                 data.dptr, data.dsize, 0, 0, 0 );
241
242         Statslog( LDAP_DEBUG_STATS,
243                 "=> ldbm_cache_store(): flags=0x%08x\n",
244                 flags, 0, 0, 0, 0 );
245 #endif /* LDBM_DEBUG */
246
247         rc = ldbm_store( db->dbc_db, key, data, flags );
248
249         pthread_mutex_unlock( &db->dbc_mutex );
250
251         return( rc );
252 }
253
254 int
255 ldbm_cache_delete(
256     struct dbcache      *db,
257     Datum               key
258 )
259 {
260         int     rc;
261
262         pthread_mutex_lock( &db->dbc_mutex );
263 #ifdef reentrant_database
264         /* wait for reader count to drop to zero - then write */
265         while ( db->dbc_readers > 0 ) {
266                 pthread_cond_wait( &db->dbc_cv, &db->dbc_mutex );
267         }
268 #endif
269
270         rc = ldbm_delete( db->dbc_db, key );
271
272         pthread_mutex_unlock( &db->dbc_mutex );
273
274         return( rc );
275 }