]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb2/txn.c
Elimination of entry- and cache-level locking in back-bdb2.
[openldap] / servers / slapd / back-bdb2 / txn.c
1 /* txn.c - TP support functions of the bdb2 backend */
2
3 #include "txn.h"
4
5
6 int
7 bdb2i_txn_head_init( BDB2_TXN_HEAD *head )
8 {
9         int             dbFile;
10         BDB2_TXN_FILES  **fileNodeH;
11
12         /*  for each fixed DB file allocate a file descriptor node and
13         initialize the file's name  */
14         fileNodeH = &head->dbFiles;
15         for ( dbFile = BDB2_DB_DN_FILE; dbFile <= BDB2_DB_OC_IDX_FILE; dbFile++ ) {
16
17                 char fileName[MAXPATHLEN];
18
19                 *fileNodeH = (BDB2_TXN_FILES *) ch_calloc( 1, sizeof( BDB2_TXN_FILES ));
20                 if ( *fileNodeH == NULL ) {
21
22                         Debug( LDAP_DEBUG_ANY, "bdb2i_txn_head_init(): out of memory!\n",
23                                         0, 0, 0 );
24                         return( 1 );
25
26                 }
27
28                 sprintf( fileName, "%s%s", bdb2i_fixed_filenames[dbFile], BDB2_SUFFIX );
29                 (*fileNodeH)->dbc_name = strdup( fileName );
30
31                 fileNodeH = &(*fileNodeH)->next;
32
33         }
34
35         return 0;
36 }
37
38
39 static void
40 bdb2i_init_db_file_cache( struct ldbminfo *li, BDB2_TXN_FILES *fileinfo )
41 {
42         struct stat st;
43         char        buf[MAXPATHLEN];
44
45         fileinfo->dbc_refcnt = 1;
46
47         sprintf( buf, "%s%s%s", li->li_directory, DEFAULT_DIRSEP,
48                                         fileinfo->dbc_name );
49         if ( stat( buf, &st ) == 0 ) {
50                 fileinfo->dbc_blksize = st.st_blksize;
51         } else {
52                 fileinfo->dbc_blksize = DEFAULT_BLOCKSIZE;
53         }
54
55         fileinfo->dbc_maxids = ( fileinfo->dbc_blksize / sizeof( ID )) -
56                         ID_BLOCK_IDS_OFFSET;
57         fileinfo->dbc_maxindirect = ( SLAPD_LDBM_MIN_MAXIDS /
58                 fileinfo->dbc_maxids ) + 1;
59
60 }
61
62
63 /*  create a DB file cache entry for a specified index attribute
64         (if not already done); the function is called during config
65         file read for all index'ed attributes; if "default" index with
66         a non-none selection is given, this is remembered for run-time
67         extension of the list of index files; the function is also
68         called before add or modify operations to check for putative
69         new "default" index files; at that time, files are also opened
70 */
71 void
72 bdb2i_txn_attr_config(
73         struct ldbminfo  *li,
74         char             *attr,
75         int              open )
76 {
77         BDB2_TXN_HEAD  *head = &li->li_txn_head;
78
79         /*  the "attribute" 'default' is special  */
80         if ( strcasecmp( attr, "default" )) {
81
82                 /*  create a new index file node, if the index is not known  already  */
83                 BDB2_TXN_FILES  **fileNodeH;
84                 char            fileName[MAXPATHLEN];
85
86                 sprintf( fileName, "%s%s", attr,  BDB2_SUFFIX );
87
88                 /*  search for the end of the list or a node describing
89                         the current attribute  */
90                 for ( fileNodeH = &head->dbFiles;
91                                 ( *fileNodeH && strcasecmp( (*fileNodeH)->dbc_name, fileName ));
92                                 fileNodeH = &(*fileNodeH)->next ) {
93
94                 }
95
96                 /*  unless we have that attribute already...  */
97                 if ( *fileNodeH == NULL ) {
98                         BDB2_TXN_FILES *p;
99
100                         Debug( LDAP_DEBUG_TRACE,
101                                         "bdb2i_txn_attr_config(): adding node for \"%s\"\n",
102                                         fileName, 0, 0 );
103
104                         /*  if we're out of memory, we have to see, how to exit...  */
105                         if ( ( *fileNodeH = p = (BDB2_TXN_FILES *)
106                                         ch_calloc( 1, sizeof( BDB2_TXN_FILES )) ) == NULL ) {
107
108                                 Debug( LDAP_DEBUG_ANY,
109                                                 "bdb2i_txn_attr_config(): out of memory -- FATAL.\n",
110                                                 0, 0, 0 );
111
112                                 /*  during configuration (no files are opened)
113                                         we can just exit, otherwise we kill ourself and
114                                         hope to shutdown cleanly...  */
115                                 if ( open ) {
116                                         pthread_kill( pthread_self(), LDAP_SIGUSR1 );
117                                 } else {
118                                         exit( 1 );
119                                 }
120                         }
121
122                         p->dbc_name = strdup( fileName );
123
124                         /*  if requested for, we have to open the DB file  */
125                         /*  BUT NOT "objectclass", 'cause that's a default index !  */
126                         if ( open && strcasecmp( fileName, "objectclass" )) {
127
128                                 /*  re-use filename to get the complete path  */
129                                 sprintf( fileName, "%s%s%s",
130                                                         li->li_directory, DEFAULT_DIRSEP, p->dbc_name );
131
132                                 /*  since we have an mpool, we should not define a cache size */
133                                 p->dbc_db = ldbm_open( fileName, LDBM_WRCREAT, li->li_mode, 0 );
134
135                                 /*  if the files could not be opened, something is wrong;
136                                         complain  */
137                                 if ( p->dbc_db == NULL ) {
138
139                                         Debug( LDAP_DEBUG_ANY,
140                                 "bdb2i_txn_open_files(): couldn't open file \"%s\" -- FATAL.\n",
141                                                 p->dbc_name, 0, 0 );
142                                         pthread_kill( pthread_self(), LDAP_SIGUSR1 );
143
144                                 }
145
146                                 bdb2i_init_db_file_cache( li, p );
147
148                                 Debug( LDAP_DEBUG_TRACE,
149                                         "bdb2i_txn_attr_config(): NEW INDEX FILE \"%s\"\n",
150                                         p->dbc_name, 0, 0 );
151
152                         }
153                 }
154
155         } else {  /*  it is "attribute" 'default'  */
156
157                 head->withDefIDX = BDB2_WITH_DEF_IDX;
158
159         }
160 }
161
162
163 /*  open the NEXTID file for read/write; if it does not exist,
164         create it (access to the file must be preceeded by a rewind)
165 */
166 static int
167 bdb2i_open_nextid( struct ldbminfo *li )
168 {
169         BDB2_TXN_HEAD   *head = &li->li_txn_head;
170         FILE            *fp = NULL;
171         char            *file = li->li_nextid_file;
172
173         /*  try to open the file for read and write  */
174         if ((( fp = fopen( file, "r+" )) == NULL ) &&
175                 (( fp = fopen( file, "w+" )) == NULL )) {
176
177                         Debug( LDAP_DEBUG_ANY,
178                                 "bdb2i_open_nextid: could not open \"%s\"\n",
179                                 file, 0, 0 );
180                         return( -1 );
181
182         }
183
184         /*  the file is open for read/write  */
185         head->nextidFP = fp;
186
187         return( 0 );
188 }
189
190
191 /*  open all DB during startup of the backend (necessary due to TP)
192         additional files may be opened during slapd life-time due to
193         default indexes (must be configured in slapd.conf;
194         see bdb2i_txn_attr_config)
195 */
196 int
197 bdb2i_txn_open_files( struct ldbminfo *li )
198 {
199         BDB2_TXN_HEAD   *head = &li->li_txn_head;
200         BDB2_TXN_FILES  *dbFile;
201         int             rc;
202
203         for ( dbFile = head->dbFiles; dbFile; dbFile = dbFile->next ) {
204                 char   fileName[MAXPATHLEN];
205
206                 sprintf( fileName, "%s%s%s",
207                                         li->li_directory, DEFAULT_DIRSEP, dbFile->dbc_name );
208
209                 /*  since we have an mpool, we should not define a cache size */
210                 dbFile->dbc_db = ldbm_open( fileName, LDBM_WRCREAT, li->li_mode, 0 );
211
212                 /*  if the files could not be opened, something is wrong; complain  */
213                 if ( dbFile->dbc_db == NULL ) {
214
215                         Debug( LDAP_DEBUG_ANY,
216                                 "bdb2i_txn_open_files(): couldn't open file \"%s\" -- FATAL.\n",
217                                 dbFile->dbc_name, 0, 0 );
218                         return( -1 );
219
220                 }
221
222                 /*  initialize the file info  */
223                 bdb2i_init_db_file_cache( li, dbFile );
224
225                 Debug( LDAP_DEBUG_TRACE, "bdb2i_txn_open_files(): OPEN INDEX \"%s\"\n",
226                                 dbFile->dbc_name, 0, 0 );
227
228         }
229
230         rc = bdb2i_open_nextid( li );
231
232         return rc;
233 }
234
235
236 /*  close the NEXTID file  */
237 static void
238 bdb2i_close_nextid( BDB2_TXN_HEAD *head )
239 {
240         fclose( head->nextidFP );
241         head->nextidFP = NULL;
242 }
243
244
245 /*  close all DB files during shutdown of the backend  */
246 void
247 bdb2i_txn_close_files( BackendDB *be )
248 {
249         struct ldbminfo  *li = (struct ldbminfo *) be->be_private;
250         BDB2_TXN_HEAD    *head = &li->li_txn_head;
251         BDB2_TXN_FILES   *dbFile;
252
253         for ( dbFile = head->dbFiles; dbFile; dbFile = dbFile->next ) {
254
255                 ldbm_close( dbFile->dbc_db );
256
257         }
258
259         bdb2i_close_nextid( head );
260
261 }
262
263
264 /*  get the db_cache structure associated with a specified
265         DB file (replaces the on-the-fly opening of files in cache_open()
266 */
267 BDB2_TXN_FILES *
268 bdb2i_get_db_file_cache( struct ldbminfo *li, char *name )
269 {
270         BDB2_TXN_HEAD  *head = &li->li_txn_head;
271         BDB2_TXN_FILES *dbFile;
272         int            dbFileNum;
273
274         Debug( LDAP_DEBUG_TRACE, "bdb2i_get_db_file_cache(): looking for file %s\n",
275                         name, 0, 0 );
276
277         for ( dbFile = head->dbFiles; dbFile; dbFile = dbFile->next ) {
278
279                 /*  we've got it  */
280                 if ( !strcasecmp( dbFile->dbc_name, name )) return( dbFile );
281
282         }
283
284         Debug( LDAP_DEBUG_ANY,
285                 "bdb2i_get_db_file_cache(): UPS, could't find \"%s\" \n", name, 0, 0 );
286
287         /*  ups, we couldn't find the file  */
288         return( NULL );
289
290 }
291
292
293 /*  check for new attribute indexes, that might have been created
294     during former runs of slapd  */
295 /*  this is called during startup of the slapd server  */
296 int
297 bdb2i_check_additional_attr_index( struct ldbminfo *li )
298 {
299         DIR            *datadir;
300         struct dirent  *file;
301
302         if ( ( datadir = opendir( li->li_directory ) ) == NULL ) {
303
304                 Debug( LDAP_DEBUG_ANY,
305         "bdb2i_check_additional_attr_index(): ERROR while opening datadir: %s\n",
306                                 strerror( errno ), 0, 0 );
307                 return( 1 );
308
309         }
310
311         for ( file = readdir( datadir ); file; file = readdir( datadir )) {
312                 char  filename[MAXPATHLEN];
313                 int   namelen;
314
315                 strcpy( filename, file->d_name );
316                 namelen = strlen( filename );
317
318                 if ( namelen > strlen( BDB2_SUFFIX )) {
319
320                         if ( !strcasecmp( filename + namelen - strlen( BDB2_SUFFIX ),
321                                                         BDB2_SUFFIX )) {
322
323                                 *(filename + namelen - strlen( BDB2_SUFFIX )) = '\0';
324                                 bdb2i_txn_attr_config( li, filename, 0 );
325
326                                 Debug( LDAP_DEBUG_TRACE, "INDEX FILE: %s\n", filename, 0, 0 );
327
328                         }
329
330                 }
331
332         }
333
334         closedir( datadir );
335
336         return 0;
337 }
338
339
340 /*  check for the addition of new attribute indexes during add  */
341 /*  this is called after startup of the slapd server  */
342 /*  DON'T WORRY ABOUT ACCESS RIGHTS, THAT MIGHT PREVENT US
343         FROM ADDING ATTRIBUTES LATER ON  */
344 void
345 bdb2i_check_default_attr_index_add( struct ldbminfo *li, Entry *e )
346 {
347         BDB2_TXN_HEAD  *head = &li->li_txn_head;
348
349         if ( head->withDefIDX == BDB2_WITH_DEF_IDX ) {
350                 Attribute   *ap;
351
352                 for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
353                         if ( strcasecmp( ap->a_type, "objectclass" ))
354                                 bdb2i_txn_attr_config( li, ap->a_type, 1 );
355                 }
356         }
357 }
358
359
360 /*  check for the addition of new attribute indexes during modify  */
361 /*  this is called after startup of the slapd server  */
362 /*  DON'T WORRY ABOUT ACCESS RIGHTS, THAT MIGHT PREVENT US
363         FROM ADDING ATTRIBUTES LATER ON  */
364 void
365 bdb2i_check_default_attr_index_mod( struct ldbminfo *li, LDAPModList *modlist )
366 {
367         BDB2_TXN_HEAD  *head = &li->li_txn_head;
368
369         if ( head->withDefIDX == BDB2_WITH_DEF_IDX ) {
370                 LDAPModList *ml;
371                 char  *default_attrs[] = { "modifytimestamp", "modifiersname", NULL };
372                 int   attr;
373
374                 for ( ml = modlist; ml != NULL; ml = ml->ml_next ) {
375                         LDAPMod *mod = &ml->ml_mod;
376
377                         if (( mod->mod_op & ~LDAP_MOD_BVALUES ) == LDAP_MOD_ADD )
378                                 if ( strcasecmp( mod->mod_type, "objectclass" ))
379                                         bdb2i_txn_attr_config( li, mod->mod_type, 1 );
380                 }
381
382                 /*  these attributes are default when modifying  */
383                 for ( attr = 0; default_attrs[attr]; attr++ ) {
384                         bdb2i_txn_attr_config( li, default_attrs[attr], 1 );
385                 }
386         }
387 }
388
389