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