~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to libdb/fileops/fop_util.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.1.79 upstream) (1.6.12 experimental)
  • Revision ID: james.westby@ubuntu.com-20100517170206-4ufr52vwrhh26yh0
Tags: 2.30.1-1ubuntu1
* Merge from debian experimental. Remaining change:
  (LP: #42199, #229669, #173703, #360344, #508494)
  + debian/control:
    - add Vcs-Bzr tag
    - don't use libgnome
    - Use Breaks instead of Conflicts against evolution 2.25 and earlier.
  + debian/evolution-data-server.install,
    debian/patches/45_libcamel_providers_version.patch:
    - use the upstream versioning, not a Debian-specific one 
  + debian/libedata-book1.2-dev.install, debian/libebackend-1.2-dev.install,
    debian/libcamel1.2-dev.install, debian/libedataserverui1.2-dev.install:
    - install html documentation
  + debian/rules:
    - don't build documentation it's shipped with the tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*-
2
 
 * See the file LICENSE for redistribution information.
3
 
 *
4
 
 * Copyright (c) 2001-2002
5
 
 *      Sleepycat Software.  All rights reserved.
6
 
 */
7
 
 
8
 
#include "db_config.h"
9
 
 
10
 
#ifndef lint
11
 
static const char revid[] = "$Id$";
12
 
#endif /* not lint */
13
 
 
14
 
#ifndef NO_SYSTEM_INCLUDES
15
 
#include <sys/types.h>
16
 
 
17
 
#include <stddef.h>
18
 
#include <stdlib.h>
19
 
#include <string.h>
20
 
#endif
21
 
 
22
 
#include "db_int.h"
23
 
#include "dbinc/db_page.h"
24
 
#include "dbinc/db_shash.h"
25
 
#include "dbinc/db_am.h"
26
 
#include "dbinc/fop.h"
27
 
#include "dbinc/lock.h"
28
 
#include "dbinc/log.h"
29
 
#include "dbinc/txn.h"
30
 
 
31
 
static int __fop_set_pgsize __P((DB *, DB_FH *, const char *));
32
 
 
33
 
/*
34
 
 * Acquire the environment meta-data lock.  The parameters are the
35
 
 * environment (ENV), the locker id to use in acquiring the lock (ID)
36
 
 * and a pointer to a DB_LOCK.
37
 
 */
38
 
#define GET_ENVLOCK(ENV, ID, L) do {                                    \
39
 
        DBT __dbt;                                                      \
40
 
        u_int32_t __lockval;                                            \
41
 
                                                                        \
42
 
        if (LOCKING_ON((ENV))) {                                        \
43
 
                __lockval = 0;                                          \
44
 
                __dbt.data = &__lockval;                                \
45
 
                __dbt.size = sizeof(__lockval);                         \
46
 
                if ((ret = (ENV)->lock_get((ENV), (ID),                 \
47
 
                    0, &__dbt, DB_LOCK_WRITE, (L))) != 0)               \
48
 
                        goto err;                                       \
49
 
        }                                                               \
50
 
} while (0)
51
 
 
52
 
#define REL_ENVLOCK(ENV, L)                                             \
53
 
        (!LOCK_ISSET(*(L)) ? 0 : (ENV)->lock_put((ENV), (L)))
54
 
 
55
 
/*
56
 
 * If our caller is doing fcntl(2) locking, then we can't close it
57
 
 * because that would discard the caller's lock.  Otherwise, close
58
 
 * the handle.
59
 
 */
60
 
#define CLOSE_HANDLE(D, F) {                                            \
61
 
        if (F_ISSET((F), DB_FH_VALID)) {                                \
62
 
                if (LF_ISSET(DB_FCNTL_LOCKING))                         \
63
 
                        (D)->saved_open_fhp = (F);                      \
64
 
                else if ((t_ret = __os_closehandle((D)->dbenv,(F))) != 0) { \
65
 
                        if (ret == 0)                                   \
66
 
                                ret = t_ret;                            \
67
 
                        goto err;                                       \
68
 
                }                                                       \
69
 
        }                                                               \
70
 
}
71
 
 
72
 
/*
73
 
 * __fop_lock_handle --
74
 
 *
75
 
 * Get the handle lock for a database.  If the envlock is specified,
76
 
 * do this as a lock_vec call that releases the enviroment lock before
77
 
 * acquiring the handle lock.
78
 
 *
79
 
 * PUBLIC: int __fop_lock_handle __P((DB_ENV *,
80
 
 * PUBLIC:     DB *, u_int32_t, db_lockmode_t, DB_LOCK *, u_int32_t));
81
 
 *
82
 
 */
83
 
int
84
 
__fop_lock_handle(dbenv, dbp, locker, mode, elock, flags)
85
 
        DB_ENV *dbenv;
86
 
        DB *dbp;
87
 
        u_int32_t locker;
88
 
        db_lockmode_t mode;
89
 
        DB_LOCK *elock;
90
 
        u_int32_t flags;
91
 
{
92
 
        DBT fileobj;
93
 
        DB_LOCKREQ reqs[2], *ereq;
94
 
        DB_LOCK_ILOCK lock_desc;
95
 
        int ret;
96
 
 
97
 
        if (!LOCKING_ON(dbenv) || F_ISSET(dbp, DB_AM_COMPENSATE))
98
 
                return (0);
99
 
 
100
 
        /*
101
 
         * If we are in recovery, the only locking we should be
102
 
         * doing is on the global environment.
103
 
         */
104
 
        if (IS_RECOVERING(dbenv)) {
105
 
                if (elock != NULL)
106
 
                        REL_ENVLOCK(dbenv, elock);
107
 
                return (0);
108
 
        }
109
 
 
110
 
        memcpy(&lock_desc.fileid, &dbp->fileid, DB_FILE_ID_LEN);
111
 
        lock_desc.pgno = dbp->meta_pgno;
112
 
        lock_desc.type = DB_HANDLE_LOCK;
113
 
 
114
 
        memset(&fileobj, 0, sizeof(fileobj));
115
 
        fileobj.data = &lock_desc;
116
 
        fileobj.size = sizeof(lock_desc);
117
 
        DB_TEST_SUBLOCKS(dbenv, flags);
118
 
        if (elock == NULL)
119
 
                ret = dbenv->lock_get(dbenv, locker,
120
 
                    flags, &fileobj, mode, &dbp->handle_lock);
121
 
        else {
122
 
                reqs[0].op = DB_LOCK_PUT;
123
 
                reqs[0].lock = *elock;
124
 
                reqs[1].op = DB_LOCK_GET;
125
 
                reqs[1].mode = mode;
126
 
                reqs[1].obj = &fileobj;
127
 
                reqs[1].timeout = 0;
128
 
                if ((ret = __lock_vec(dbenv,
129
 
                    locker, flags, reqs, 2, &ereq)) == 0) {
130
 
                        dbp->handle_lock = reqs[1].lock;
131
 
                        LOCK_INIT(*elock);
132
 
                } else if (ereq != reqs)
133
 
                        LOCK_INIT(*elock);
134
 
        }
135
 
 
136
 
        dbp->cur_lid = locker;
137
 
        return (ret);
138
 
}
139
 
 
140
 
/*
141
 
 * __fop_file_setup --
142
 
 *
143
 
 * Perform all the needed checking and locking to open up or create a
144
 
 * file.
145
 
 *
146
 
 * There's a reason we don't push this code down into the buffer cache.
147
 
 * The problem is that there's no information external to the file that
148
 
 * we can use as a unique ID.  UNIX has dev/inode pairs, but they are
149
 
 * not necessarily unique after reboot, if the file was mounted via NFS.
150
 
 * Windows has similar problems, as the FAT filesystem doesn't maintain
151
 
 * dev/inode numbers across reboot.  So, we must get something from the
152
 
 * file we can use to ensure that, even after a reboot, the file we're
153
 
 * joining in the cache is the right file for us to join.  The solution
154
 
 * we use is to maintain a file ID that's stored in the database, and
155
 
 * that's why we have to open and read the file before calling into the
156
 
 * buffer cache or obtaining a lock (we use this unique fileid to lock
157
 
 * as well as to identify like files in the cache).
158
 
 *
159
 
 * PUBLIC: int __fop_file_setup __P((DB *,
160
 
 * PUBLIC:     DB_TXN *, const char *, int, u_int32_t, u_int32_t *));
161
 
 */
162
 
int
163
 
__fop_file_setup(dbp, txn, name, mode, flags, retidp)
164
 
        DB *dbp;
165
 
        DB_TXN *txn;
166
 
        const char *name;
167
 
        int mode;
168
 
        u_int32_t flags, *retidp;
169
 
{
170
 
        DB_ENV *dbenv;
171
 
        DB_FH fh, *fhp;
172
 
        DB_LOCK elock, tmp_lock;
173
 
        DB_TXN *stxn;
174
 
        char *real_name, *real_tmpname, *tmpname;
175
 
        db_lockmode_t lmode;
176
 
        int created_fhp, created_locker, ret, tmp_created, t_ret, truncating;
177
 
        size_t len;
178
 
        u_int32_t locker, oflags;
179
 
        u_int8_t mbuf[DBMETASIZE];
180
 
 
181
 
        DB_ASSERT(name != NULL);
182
 
 
183
 
        *retidp = TXN_INVALID;
184
 
 
185
 
        dbenv = dbp->dbenv;
186
 
        LOCK_INIT(elock);
187
 
        LOCK_INIT(tmp_lock);
188
 
        stxn = NULL;
189
 
        created_fhp = created_locker = 0;
190
 
        real_name = real_tmpname = tmpname = NULL;
191
 
        tmp_created = truncating = 0;
192
 
 
193
 
        /*
194
 
         * If we open a file handle and our caller is doing fcntl(2) locking,
195
 
         * we can't close it because that would discard the caller's lock.
196
 
         * Save it until we close or refresh the DB handle.
197
 
         */
198
 
        if (LF_ISSET(DB_FCNTL_LOCKING)) {
199
 
                if ((ret = __os_malloc(dbenv, sizeof(*fhp), &fhp)) != 0)
200
 
                        return (ret);
201
 
                created_fhp = 1;
202
 
        } else
203
 
                fhp = &fh;
204
 
        memset(fhp, 0, sizeof(*fhp));
205
 
 
206
 
        /*
207
 
         * Get a lockerid for this handle.  There are paths through queue
208
 
         * rename and remove where this dbp already has a locker, so make
209
 
         * sure we don't clobber it and conflict.
210
 
         */
211
 
        if (LOCKING_ON(dbenv) &&
212
 
            !F_ISSET(dbp, DB_AM_COMPENSATE) && dbp->lid == DB_LOCK_INVALIDID) {
213
 
                if ((ret = __lock_id(dbenv, &dbp->lid)) != 0)
214
 
                        goto err;
215
 
                created_locker = 1;
216
 
        }
217
 
 
218
 
        locker = txn == NULL ? dbp->lid : txn->txnid;
219
 
 
220
 
        /* Get the real backing file name. */
221
 
        if ((ret = __db_appname(dbenv,
222
 
            DB_APP_DATA, name, 0, NULL, &real_name)) != 0)
223
 
                goto err;
224
 
 
225
 
        /* Fill in the default file mode. */
226
 
        if (mode == 0)
227
 
                mode = __db_omode("rwrw--");
228
 
 
229
 
        oflags = 0;
230
 
        if (LF_ISSET(DB_RDONLY))
231
 
                oflags |= DB_OSO_RDONLY;
232
 
 
233
 
retry:  if (!F_ISSET(dbp, DB_AM_COMPENSATE))
234
 
                GET_ENVLOCK(dbenv, locker, &elock);
235
 
        if ((ret = __os_exists(real_name, NULL)) == 0) {
236
 
                if (LF_ISSET(DB_EXCL)) {
237
 
                        ret = EEXIST;
238
 
                        goto err;
239
 
                }
240
 
 
241
 
                /*
242
 
                 * This is special handling for applications that
243
 
                 * are locking outside of Berkeley DB (e.g., Sendmail,
244
 
                 * Postfix).  If we are relying on external FCNTL
245
 
                 * locking and we're going to truncate the file, we
246
 
                 * cannot first open the file to verify that it is
247
 
                 * a DB file and then close/reopen to do the truncate
248
 
                 * since that will lose the external FCNTL lock.
249
 
                 * So, we special case it and leap right into the
250
 
                 * truncate code.
251
 
                 */
252
 
                if (LF_ISSET(DB_FCNTL_LOCKING) && LF_ISSET(DB_TRUNCATE))
253
 
                        goto do_trunc;
254
 
 
255
 
reopen:         ret = __fop_read_meta(dbenv, real_name,
256
 
                    mbuf, sizeof(mbuf), fhp,
257
 
                    LF_ISSET(DB_FCNTL_LOCKING) && txn == NULL ? 1 : 0,
258
 
                    &len, oflags);
259
 
                /*
260
 
                 * This is special handling for applications that are doing
261
 
                 * file locking outside of Berkeley DB (e.g., Sendmail,
262
 
                 * Postfix).  So, if you're doing FCNTL_LOCKING and are non
263
 
                 * transactional, we're going to treat 0-length files as a
264
 
                 * special case and let you proceed.
265
 
                 */
266
 
                if (ret != 0 &&
267
 
                    LF_ISSET(DB_FCNTL_LOCKING) && txn == NULL && len == 0) {
268
 
                        tmpname = (char *)real_name;
269
 
                        real_name = NULL;
270
 
                        goto creat2;
271
 
                }
272
 
 
273
 
                if (ret != 0)
274
 
                        goto err;
275
 
 
276
 
                if ((ret = __db_meta_setup(dbenv,
277
 
                    dbp, real_name, (DBMETA *)mbuf, flags, 1)) != 0)
278
 
                        goto err;
279
 
 
280
 
                /* Now, get our handle lock. */
281
 
                lmode = LF_ISSET(DB_TRUNCATE) ? DB_LOCK_WRITE : DB_LOCK_READ;
282
 
                if ((ret = __fop_lock_handle(dbenv,
283
 
                    dbp, locker, lmode, NULL, DB_LOCK_NOWAIT)) == 0) {
284
 
                        if ((ret = REL_ENVLOCK(dbenv, &elock)) != 0)
285
 
                                goto err;
286
 
                } else {
287
 
                        /*
288
 
                         * If someone is doing FCNTL locking outside of us,
289
 
                         * then we should never have a lock conflict and
290
 
                         * should never get to here.  We need to assert that
291
 
                         * because we are about to close the fd which will
292
 
                         * release the FCNTL locks.
293
 
                         */
294
 
                        DB_ASSERT(!LF_ISSET(DB_FCNTL_LOCKING));
295
 
                        if ((ret = __os_closehandle(dbenv, fhp)) != 0)
296
 
                                goto err;
297
 
                        ret = __fop_lock_handle(dbenv,
298
 
                            dbp, locker, lmode, &elock, 0);
299
 
                        if (ret == DB_LOCK_NOTEXIST)
300
 
                                goto retry;
301
 
                        if (ret != 0)
302
 
                                goto err;
303
 
                        /*
304
 
                         * XXX I need to convince myself that I don't need
305
 
                         * to re-read the metadata page here.
306
 
                         * XXX If you do need to re-read it you'd better
307
 
                         * decrypt it too...
308
 
                         */
309
 
                        if ((ret = __os_open(dbenv, real_name, 0, 0, fhp)) != 0)
310
 
                                goto err;
311
 
                }
312
 
 
313
 
                /*
314
 
                 * Check for a truncate which needs to leap over to the
315
 
                 * create case.
316
 
                 */
317
 
                if (LF_ISSET(DB_TRUNCATE)) {
318
 
                        /*
319
 
                         * Sadly, we need to close and reopen the handle
320
 
                         * in order to do the actual truncate.  We couldn't
321
 
                         * do the truncate on the initial open because we
322
 
                         * needed to read the old file-id in order to lock.
323
 
                         */
324
 
                        if ((ret = __os_closehandle(dbenv, fhp)) != 0)
325
 
                                goto err;
326
 
do_trunc:               if ((ret = __os_open(dbenv,
327
 
                            real_name, DB_OSO_TRUNC, 0, fhp)) != 0)
328
 
                                goto err;
329
 
                        /*
330
 
                         * This is not-transactional, so we'll do the
331
 
                         * open/create in-place.
332
 
                         */
333
 
                        tmp_lock = dbp->handle_lock;
334
 
                        truncating = 1;
335
 
                        tmpname = (char *)name;
336
 
                        goto creat2;
337
 
                }
338
 
 
339
 
                /*
340
 
                 * Check for a file in the midst of a rename
341
 
                 */
342
 
                if (F_ISSET(dbp, DB_AM_IN_RENAME)) {
343
 
                        if (LF_ISSET(DB_CREATE)) {
344
 
                                F_CLR(dbp, DB_AM_IN_RENAME);
345
 
                                goto create;
346
 
                        } else {
347
 
                                ret = ENOENT;
348
 
                                goto err;
349
 
                        }
350
 
                }
351
 
 
352
 
                CLOSE_HANDLE(dbp, fhp);
353
 
                goto done;
354
 
        }
355
 
 
356
 
        /* File does not exist. */
357
 
        if (!LF_ISSET(DB_CREATE))
358
 
                goto err;
359
 
        ret = 0;
360
 
 
361
 
        /*
362
 
         * Need to create file; we need to set up the file,
363
 
         * the fileid and the locks.  Then we need to call
364
 
         * the appropriate routines to create meta-data pages.
365
 
         */
366
 
        if ((ret = REL_ENVLOCK(dbenv, &elock)) != 0)
367
 
                goto err;
368
 
 
369
 
create: if ((ret = __db_backup_name(dbenv, name, txn, &tmpname)) != 0)
370
 
                goto err;
371
 
        if (TXN_ON(dbenv) && txn != NULL &&
372
 
            (ret = dbenv->txn_begin(dbenv, txn, &stxn, 0)) != 0)
373
 
                goto err;
374
 
        if ((ret = __fop_create(dbenv,
375
 
            stxn, fhp, tmpname, DB_APP_DATA, mode)) != 0)
376
 
                goto err;
377
 
        tmp_created = 1;
378
 
creat2: if ((ret = __db_appname(dbenv,
379
 
            DB_APP_DATA, tmpname, 0, NULL, &real_tmpname)) != 0)
380
 
                goto err;
381
 
 
382
 
        /* Set the pagesize if it isn't yet set. */
383
 
        if (dbp->pgsize == 0 &&
384
 
            (ret = __fop_set_pgsize(dbp, fhp, real_tmpname)) != 0)
385
 
                goto errmsg;
386
 
 
387
 
        /* Construct a file_id. */
388
 
        if ((ret = __os_fileid(dbenv, real_tmpname, 1, dbp->fileid)) != 0)
389
 
                goto errmsg;
390
 
 
391
 
        if ((ret = __db_new_file(dbp, stxn, fhp, tmpname)) != 0)
392
 
                goto err;
393
 
        CLOSE_HANDLE(dbp, fhp);
394
 
 
395
 
        /* Now move the file into place. */
396
 
        if (!F_ISSET(dbp, DB_AM_COMPENSATE))
397
 
                GET_ENVLOCK(dbenv, locker, &elock);
398
 
        if (!truncating && __os_exists(real_name, NULL) == 0) {
399
 
                /*
400
 
                 * Someone managed to create the file; remove our temp
401
 
                 * and try to open the file that now exists.
402
 
                 */
403
 
                (void)__fop_remove(dbenv,
404
 
                    NULL, dbp->fileid, tmpname, DB_APP_DATA);
405
 
                if (LOCKING_ON(dbenv))
406
 
                        dbenv->lock_put(dbenv, &dbp->handle_lock);
407
 
                LOCK_INIT(dbp->handle_lock);
408
 
 
409
 
                /* If we have a saved handle; close it. */
410
 
                if (LF_ISSET(DB_FCNTL_LOCKING))
411
 
                        (void)__os_closehandle(dbenv, fhp);
412
 
                if (stxn != NULL) {
413
 
                        ret = stxn->abort(stxn);
414
 
                        stxn = NULL;
415
 
                }
416
 
                if (ret != 0)
417
 
                        goto err;
418
 
                goto reopen;
419
 
        }
420
 
 
421
 
        /* We've successfully created, move the file into place. */
422
 
        if ((ret = __fop_lock_handle(dbenv,
423
 
            dbp, locker, DB_LOCK_WRITE, &elock, 0)) != 0)
424
 
                goto err;
425
 
        if (!truncating && (ret = __fop_rename(dbenv,
426
 
            stxn, tmpname, name, dbp->fileid, DB_APP_DATA)) != 0)
427
 
                goto err;
428
 
 
429
 
        /* If this was a truncate; release lock on the old file. */
430
 
        if (LOCK_ISSET(tmp_lock) && (ret = __lock_put(dbenv, &tmp_lock)) != 0)
431
 
                goto err;
432
 
 
433
 
        if (stxn != NULL) {
434
 
                *retidp = stxn->txnid;
435
 
                ret = stxn->commit(stxn, 0);
436
 
                stxn = NULL;
437
 
        } else
438
 
                *retidp = TXN_INVALID;
439
 
 
440
 
        if (ret != 0)
441
 
                goto err;
442
 
 
443
 
        F_SET(dbp, DB_AM_CREATED);
444
 
 
445
 
        if (0) {
446
 
errmsg:         __db_err(dbenv, "%s: %s", name, db_strerror(ret));
447
 
 
448
 
err:            if (stxn != NULL)
449
 
                        (void)stxn->abort(stxn);
450
 
                if (tmp_created && txn == NULL)
451
 
                        (void)__fop_remove(dbenv,
452
 
                            NULL, NULL, tmpname, DB_APP_DATA);
453
 
                if (F_ISSET(fhp, DB_FH_VALID))
454
 
                        CLOSE_HANDLE(dbp, fhp);
455
 
                if (LOCK_ISSET(tmp_lock))
456
 
                        __lock_put(dbenv, &tmp_lock);
457
 
                if (LOCK_ISSET(dbp->handle_lock) && txn == NULL)
458
 
                        __lock_put(dbenv, &dbp->handle_lock);
459
 
                if (LOCK_ISSET(elock))
460
 
                        (void)REL_ENVLOCK(dbenv, &elock);
461
 
                if (created_locker) {
462
 
                        (void)__lock_id_free(dbenv, dbp->lid);
463
 
                        dbp->lid = DB_LOCK_INVALIDID;
464
 
                }
465
 
                if (created_fhp && !F_ISSET(fhp, DB_FH_VALID))
466
 
                        __os_free(dbenv, fhp);
467
 
        }
468
 
 
469
 
done:   /*
470
 
         * There are cases where real_name and tmpname take on the
471
 
         * exact same string, so we need to make sure that we do not
472
 
         * free twice.
473
 
         */
474
 
        if (!truncating && tmpname != NULL && tmpname != real_name)
475
 
                __os_free(dbenv, tmpname);
476
 
        if (real_name != NULL)
477
 
                __os_free(dbenv, real_name);
478
 
        if (real_tmpname != NULL)
479
 
                __os_free(dbenv, real_tmpname);
480
 
 
481
 
        return (ret);
482
 
}
483
 
 
484
 
/*
485
 
 * __fop_set_pgsize --
486
 
 *      Set the page size based on file information.
487
 
 */
488
 
static int
489
 
__fop_set_pgsize(dbp, fhp, name)
490
 
        DB *dbp;
491
 
        DB_FH *fhp;
492
 
        const char *name;
493
 
{
494
 
        DB_ENV *dbenv;
495
 
        u_int32_t iopsize;
496
 
        int ret;
497
 
 
498
 
        dbenv = dbp->dbenv;
499
 
 
500
 
        /*
501
 
         * Use the filesystem's optimum I/O size as the pagesize if a pagesize
502
 
         * not specified.  Some filesystems have 64K as their optimum I/O size,
503
 
         * but as that results in fairly large default caches, we limit the
504
 
         * default pagesize to 16K.
505
 
         */
506
 
        if ((ret = __os_ioinfo(dbenv, name, fhp, NULL, NULL, &iopsize)) != 0) {
507
 
                __db_err(dbenv, "%s: %s", name, db_strerror(ret));
508
 
                return (ret);
509
 
        }
510
 
        if (iopsize < 512)
511
 
                iopsize = 512;
512
 
        if (iopsize > 16 * 1024)
513
 
                iopsize = 16 * 1024;
514
 
 
515
 
        /*
516
 
         * Sheer paranoia, but we don't want anything that's not a power-of-2
517
 
         * (we rely on that for alignment of various types on the pages), and
518
 
         * we want a multiple of the sector size as well.  If the value
519
 
         * we got out of __os_ioinfo looks bad, use a default instead.
520
 
         */
521
 
        if (!IS_VALID_PAGESIZE(iopsize))
522
 
                iopsize = DB_DEF_IOSIZE;
523
 
 
524
 
        dbp->pgsize = iopsize;
525
 
        F_SET(dbp, DB_AM_PGDEF);
526
 
 
527
 
        return (0);
528
 
}
529
 
 
530
 
/*
531
 
 * __fop_subdb_setup --
532
 
 *
533
 
 * Subdb setup is significantly simpler than file setup.  In terms of
534
 
 * locking, for the duration of the operation/transaction, the locks on
535
 
 * the meta-data page will suffice to protect us from simultaneous operations
536
 
 * on the sub-database.  Before we complete the operation though, we'll get a
537
 
 * handle lock on the subdatabase so that on one else can try to remove it
538
 
 * while we've got it open.  We use an object that looks like the meta-data
539
 
 * page lock with a different type (DB_HANDLE_LOCK) for the long-term handle.
540
 
 * locks.
541
 
 *
542
 
 * PUBLIC: int __fop_subdb_setup __P((DB *, DB_TXN *,
543
 
 * PUBLIC:     const char *, const char *, int, u_int32_t));
544
 
 */
545
 
int
546
 
__fop_subdb_setup(dbp, txn, mname, name, mode, flags)
547
 
        DB *dbp;
548
 
        DB_TXN *txn;
549
 
        const char *mname, *name;
550
 
        int mode;
551
 
        u_int32_t flags;
552
 
{
553
 
        DB *mdbp;
554
 
        DB_ENV *dbenv;
555
 
        int do_remove, ret;
556
 
 
557
 
        mdbp = NULL;
558
 
        dbenv = dbp->dbenv;
559
 
 
560
 
        if ((ret = __db_master_open(dbp, txn, mname, flags, mode, &mdbp)) != 0)
561
 
                return (ret);
562
 
 
563
 
        /*
564
 
         * We are going to close this instance of the master, so we can
565
 
         * steal its handle instead of reopening a handle on the database.
566
 
         */
567
 
        if (LF_ISSET(DB_FCNTL_LOCKING)) {
568
 
                dbp->saved_open_fhp = mdbp->saved_open_fhp;
569
 
                mdbp->saved_open_fhp = NULL;
570
 
        }
571
 
 
572
 
        /* Now copy the pagesize. */
573
 
        dbp->pgsize = mdbp->pgsize;
574
 
        F_SET(dbp, DB_AM_SUBDB);
575
 
 
576
 
        if (name != NULL && (ret = __db_master_update(mdbp, dbp, txn,
577
 
            name, dbp->type, MU_OPEN, NULL, flags)) != 0)
578
 
                goto err;
579
 
 
580
 
        /*
581
 
         * Hijack the master's locker ID as well, so that our locks don't
582
 
         * conflict with the master's.  Since we're closing the master,
583
 
         * that lid would just have been freed anyway.  Once we've gotten
584
 
         * the locker id, we need to acquire the handle lock for this
585
 
         * subdatabase.
586
 
         */
587
 
        dbp->lid = mdbp->lid;
588
 
        mdbp->lid = DB_LOCK_INVALIDID;
589
 
 
590
 
        DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOG, ret, mname);
591
 
 
592
 
        /*
593
 
         * We copy our fileid from our master so that we all open
594
 
         * the same file in mpool.  We'll use the meta-pgno to lock
595
 
         * so that we end up with different handle locks.
596
 
         */
597
 
 
598
 
        memcpy(dbp->fileid, mdbp->fileid, DB_FILE_ID_LEN);
599
 
        if ((ret = __fop_lock_handle(dbenv, dbp,
600
 
            txn == NULL ? dbp->lid : txn->txnid,
601
 
            F_ISSET(dbp, DB_AM_CREATED) || LF_ISSET(DB_WRITEOPEN) ?
602
 
            DB_LOCK_WRITE : DB_LOCK_READ, NULL, 0)) != 0)
603
 
                goto err;
604
 
 
605
 
        if ((ret = __db_init_subdb(mdbp, dbp, name, txn)) != 0)
606
 
                goto err;
607
 
 
608
 
        /*
609
 
         * In the file create case, these happen in separate places so we have
610
 
         * two different tests.  They end up in the same place for subdbs, but
611
 
         * for compatibility with file testing, we put them both here anyway.
612
 
         */
613
 
        DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOGMETA, ret, mname);
614
 
        DB_TEST_RECOVERY(dbp, DB_TEST_POSTSYNC, ret, mname);
615
 
 
616
 
        /*
617
 
         * File exists and we have the appropriate locks; we should now
618
 
         * process a normal open.
619
 
         */
620
 
        if (F_ISSET(mdbp, DB_AM_CREATED)) {
621
 
                F_SET(dbp, DB_AM_CREATED_MSTR);
622
 
                F_CLR(mdbp, DB_AM_DISCARD);
623
 
        }
624
 
 
625
 
        /*
626
 
         * The master's handle lock is under the control of the
627
 
         * subdb (it acquired the master's locker).  We want to
628
 
         * keep the master's handle lock so that no one can remove
629
 
         * the file while the subdb is open.  If we register the
630
 
         * trade event and then invalidate the copy of the lock
631
 
         * in the master's handle, that will accomplish this.  However,
632
 
         * before we register this event, we'd better remove any
633
 
         * events that we've already registered for the master.
634
 
         */
635
 
 
636
 
        if (!F_ISSET(dbp, DB_AM_RECOVER) && txn != NULL) {
637
 
                /* Unregister old master events. */
638
 
                 __txn_remlock(dbenv,
639
 
                    txn, &mdbp->handle_lock, DB_LOCK_INVALIDID);
640
 
 
641
 
                /* Now register the new event. */
642
 
                if ((ret = __txn_lockevent(dbenv,
643
 
                    txn, dbp, &mdbp->handle_lock, dbp->lid)) != 0)
644
 
                        goto err;
645
 
        }
646
 
        LOCK_INIT(mdbp->handle_lock);
647
 
        return (__db_close_i(mdbp, txn, 0));
648
 
 
649
 
err:
650
 
DB_TEST_RECOVERY_LABEL
651
 
        if (LOCK_ISSET(dbp->handle_lock) && txn == NULL)
652
 
                __lock_put(dbenv, &dbp->handle_lock);
653
 
 
654
 
        /* If we created the master file then we need to remove it.  */
655
 
        if (mdbp != NULL) {
656
 
                do_remove = F_ISSET(mdbp, DB_AM_CREATED) ? 1 : 0;
657
 
                if (do_remove)
658
 
                        F_SET(mdbp, DB_AM_DISCARD);
659
 
                (void)__db_close_i(mdbp, txn, 0);
660
 
                if (do_remove) {
661
 
                        (void)db_create(&mdbp, dbp->dbenv, 0);
662
 
                        (void)__db_remove_i(mdbp, txn, mname, NULL);
663
 
                }
664
 
        }
665
 
        return (ret);
666
 
}
667
 
 
668
 
/*
669
 
 * __fop_remove_setup --
670
 
 *      Open handle appropriately and lock for removal of a database file.
671
 
 *
672
 
 * PUBLIC: int __fop_remove_setup __P((DB *,
673
 
 * PUBLIC:      DB_TXN *, const char *, u_int32_t));
674
 
 */
675
 
int
676
 
__fop_remove_setup(dbp, txn, name, flags)
677
 
        DB *dbp;
678
 
        DB_TXN *txn;
679
 
        const char *name;
680
 
        u_int32_t flags;
681
 
{
682
 
        DB_ENV *dbenv;
683
 
        DB_FH *fhp;
684
 
        DB_LOCK elock;
685
 
        u_int8_t mbuf[DBMETASIZE];
686
 
        int ret;
687
 
 
688
 
        COMPQUIET(flags, 0);
689
 
        dbenv = dbp->dbenv;
690
 
        PANIC_CHECK(dbenv);
691
 
        LOCK_INIT(elock);
692
 
 
693
 
        /* Create locker if necessary. */
694
 
        if (LOCKING_ON(dbenv)) {
695
 
                if (txn != NULL)
696
 
                        dbp->lid = txn->txnid;
697
 
                else if (dbp->lid == DB_LOCK_INVALIDID) {
698
 
                        if ((ret = __lock_id(dbenv, &dbp->lid)) != 0)
699
 
                                goto err;
700
 
                }
701
 
        }
702
 
 
703
 
        /*
704
 
         * We are about to open a file handle and then possibly close it.
705
 
         * We cannot close handles if we are doing FCNTL locking.  However,
706
 
         * there is no way to pass the FCNTL flag into this routine via the
707
 
         * user API.  The only way we can get in here and be doing FCNTL
708
 
         * locking is if we are trying to clean up an open that was called
709
 
         * with FCNTL locking.  In that case, the save_fhp should already be
710
 
         * set.  So, we use that field to tell us if we need to make sure
711
 
         * that we shouldn't close the handle.
712
 
         */
713
 
        fhp = dbp->saved_open_fhp;
714
 
        DB_ASSERT(LF_ISSET(DB_FCNTL_LOCKING) ||
715
 
            fhp == NULL || !F_ISSET(fhp, DB_FH_VALID));
716
 
 
717
 
        /*
718
 
         * Lock environment to protect file open.  That will enable us to
719
 
         * read the meta-data page and get the fileid so that we can lock
720
 
         * the handle.
721
 
         */
722
 
        GET_ENVLOCK(dbenv, dbp->lid, &elock);
723
 
        if ((ret = __fop_read_meta(dbenv,
724
 
            name, mbuf, sizeof(mbuf), fhp, 0, NULL, 0)) != 0)
725
 
                goto err;
726
 
 
727
 
        if ((ret =
728
 
            __db_meta_setup(dbenv, dbp, name, (DBMETA *)mbuf, flags, 1)) != 0)
729
 
                goto err;
730
 
 
731
 
        /* Now, release the environment and get the handle lock. */
732
 
        if ((ret = __fop_lock_handle(dbenv,
733
 
            dbp, dbp->lid, DB_LOCK_WRITE, &elock, 0)) != 0)
734
 
                goto err;
735
 
 
736
 
        return (0);
737
 
 
738
 
err:    (void)REL_ENVLOCK(dbenv, &elock);
739
 
        return (ret);
740
 
}
741
 
 
742
 
/*
743
 
 * __fop_read_meta --
744
 
 *      Read the meta-data page from a file and return it in buf.  The
745
 
 * open file handle is returned in fhp.
746
 
 *
747
 
 * PUBLIC: int __fop_read_meta __P((DB_ENV *, const char *,
748
 
 * PUBLIC:     u_int8_t *, size_t, DB_FH *, int, size_t *, u_int32_t));
749
 
 */
750
 
int
751
 
__fop_read_meta(dbenv, name, buf, size, fhp, errok, nbytesp, flags)
752
 
        DB_ENV *dbenv;
753
 
        const char *name;
754
 
        u_int8_t *buf;
755
 
        size_t size;
756
 
        DB_FH *fhp;
757
 
        int errok;
758
 
        size_t *nbytesp;
759
 
        u_int32_t flags;
760
 
{
761
 
        DB_FH fh, *lfhp;
762
 
        size_t nr;
763
 
        int myfhp, ret;
764
 
 
765
 
        nr = 0;
766
 
        myfhp = 0;
767
 
        memset(&fh, 0, sizeof(fh));
768
 
        lfhp = fhp == NULL ? &fh : fhp;
769
 
        myfhp = F_ISSET(lfhp, DB_FH_VALID);
770
 
        if (!myfhp && (ret = __os_open(dbenv, name, flags, 0, lfhp)) != 0)
771
 
                goto err;
772
 
        if ((ret = __os_read(dbenv, lfhp, buf, size, &nr)) != 0) {
773
 
                if (!errok)
774
 
                        __db_err(dbenv, "%s: %s", name, db_strerror(ret));
775
 
                goto err;
776
 
        }
777
 
 
778
 
        if (nr != size) {
779
 
                if (!errok)
780
 
                        __db_err(dbenv,
781
 
                            "%s: unexpected file type or format", name);
782
 
                ret = EINVAL;
783
 
                goto err;
784
 
        }
785
 
 
786
 
err:    /*
787
 
         * On error, we would like to close the handle.  However, if the
788
 
         * handle was opened in the caller, we cannot.  If there is no error,
789
 
         * then we only close the handle if we opened it here.
790
 
         */
791
 
        if (!myfhp && F_ISSET((lfhp), DB_FH_VALID) && (ret != 0 || fhp == NULL))
792
 
                __os_closehandle(dbenv, lfhp);
793
 
 
794
 
        if (nbytesp != NULL)
795
 
                *nbytesp = nr;
796
 
        return (ret);
797
 
}
798
 
 
799
 
/*
800
 
 * __fop_dummy --
801
 
 *      This implements the creation and name swapping of dummy files that
802
 
 * we use for remove and rename (remove is simply a rename with a delayed
803
 
 * remove).
804
 
 *
805
 
 * PUBLIC: int __fop_dummy __P((DB *,
806
 
 * PUBLIC:     DB_TXN *, const char *, const char *, u_int32_t));
807
 
 */
808
 
int
809
 
__fop_dummy(dbp, txn, old, new, flags)
810
 
        DB *dbp;
811
 
        DB_TXN *txn;
812
 
        const char *old, *new;
813
 
        u_int32_t flags;
814
 
{
815
 
        DB *tmpdbp;
816
 
        DB_ENV *dbenv;
817
 
        DB_LOCK elock;
818
 
        DB_LSN lsn;
819
 
        DBT fiddbt, namedbt, tmpdbt;
820
 
        DB_TXN *stxn;
821
 
        char *back;
822
 
        char *realback, *realnew, *realold;
823
 
        int ret, t_ret;
824
 
        u_int8_t mbuf[DBMETASIZE];
825
 
        u_int32_t locker, stxnid;
826
 
 
827
 
        dbenv = dbp->dbenv;
828
 
        LOCK_INIT(elock);
829
 
        realback = NULL;
830
 
        realnew = NULL;
831
 
        realold = NULL;
832
 
        back = NULL;
833
 
        stxn = NULL;
834
 
        tmpdbp = NULL;
835
 
 
836
 
        DB_ASSERT(txn != NULL);
837
 
        locker = txn->txnid;
838
 
 
839
 
        /* Begin sub transaction to encapsulate the rename. */
840
 
        if (TXN_ON(dbenv) &&
841
 
            (ret = dbenv->txn_begin(dbenv, txn, &stxn, 0)) != 0)
842
 
                goto err;
843
 
 
844
 
        /* We need to create a dummy file as a place holder. */
845
 
        if ((ret = __db_backup_name(dbenv, new, stxn, &back)) != 0)
846
 
                goto err;
847
 
        if ((ret = __db_appname(dbenv,
848
 
            DB_APP_DATA, back, flags, NULL, &realback)) != 0)
849
 
                goto err;
850
 
        if ((ret = __fop_create(dbenv, stxn, NULL, back, DB_APP_DATA, 0)) != 0)
851
 
                goto err;
852
 
 
853
 
        memset(mbuf, 0, sizeof(mbuf));
854
 
        if ((ret =
855
 
            __os_fileid(dbenv, realback, 1, ((DBMETA *)mbuf)->uid)) != 0)
856
 
                goto err;
857
 
        ((DBMETA *)mbuf)->magic = DB_RENAMEMAGIC;
858
 
        if ((ret = __fop_write(dbenv,
859
 
            stxn, back, DB_APP_DATA, NULL, 0, mbuf, DBMETASIZE, 1)) != 0)
860
 
                goto err;
861
 
 
862
 
        /* Create a dummy dbp handle. */
863
 
        if ((ret = db_create(&tmpdbp, dbenv, 0)) != 0)
864
 
                goto err;
865
 
        memcpy(&tmpdbp->fileid, ((DBMETA *)mbuf)->uid, DB_FILE_ID_LEN);
866
 
 
867
 
        /* Now, lock the name space while we initialize this file. */
868
 
        if ((ret = __db_appname(dbenv,
869
 
            DB_APP_DATA, new, 0, NULL, &realnew)) != 0)
870
 
                goto err;
871
 
        GET_ENVLOCK(dbenv, locker, &elock);
872
 
        if (__os_exists(realnew, NULL) == 0) {
873
 
                ret = EEXIST;
874
 
                goto err;
875
 
        }
876
 
 
877
 
        /*
878
 
         * While we have the namespace locked, do the renames and then
879
 
         * swap for the handle lock.
880
 
         */
881
 
        if ((ret = __fop_rename(dbenv,
882
 
            stxn, old, new, dbp->fileid, DB_APP_DATA)) != 0)
883
 
                goto err;
884
 
        if ((ret = __fop_rename(dbenv,
885
 
            stxn, back, old, tmpdbp->fileid, DB_APP_DATA)) != 0)
886
 
                goto err;
887
 
        if ((ret = __fop_lock_handle(dbenv,
888
 
            tmpdbp, locker, DB_LOCK_WRITE, &elock, 0)) != 0)
889
 
                goto err;
890
 
 
891
 
        /*
892
 
         * We just acquired a transactional lock on the tmp handle.
893
 
         * We need to null out the tmp handle's lock so that it
894
 
         * doesn't create problems for us in the close path.
895
 
         */
896
 
        LOCK_INIT(tmpdbp->handle_lock);
897
 
 
898
 
        if (stxn != NULL) {
899
 
                /* Commit the child. */
900
 
                stxnid = stxn->txnid;
901
 
                ret = stxn->commit(stxn, 0);
902
 
                stxn = NULL;
903
 
 
904
 
                /* Now log the child information in the parent. */
905
 
                memset(&fiddbt, 0, sizeof(fiddbt));
906
 
                memset(&tmpdbt, 0, sizeof(fiddbt));
907
 
                memset(&namedbt, 0, sizeof(namedbt));
908
 
                fiddbt.data = dbp->fileid;
909
 
                fiddbt.size = DB_FILE_ID_LEN;
910
 
                tmpdbt.data = tmpdbp->fileid;
911
 
                tmpdbt.size = DB_FILE_ID_LEN;
912
 
                namedbt.data = (void *)old;
913
 
                namedbt.size = (u_int32_t)strlen(old) + 1;
914
 
                if ((t_ret =
915
 
                    __fop_file_remove_log(dbenv, txn, &lsn, 0, &fiddbt,
916
 
                    &tmpdbt, &namedbt, DB_APP_DATA, stxnid)) != 0 && ret == 0)
917
 
                        ret = t_ret;
918
 
        }
919
 
 
920
 
        /* This is a delayed delete of the dummy file. */
921
 
        if ((ret = __db_appname(dbenv,
922
 
            DB_APP_DATA, old, flags, NULL, &realold)) != 0)
923
 
                goto err;
924
 
        if ((ret = __txn_remevent(dbenv, txn, realold, NULL)) != 0)
925
 
                goto err;
926
 
 
927
 
err:    (void)REL_ENVLOCK(dbenv, &elock);
928
 
        if (stxn != NULL)
929
 
                (void)stxn->abort(stxn);
930
 
        if (tmpdbp != NULL &&
931
 
            (t_ret = __db_close_i(tmpdbp, NULL, 0)) != 0 && ret == 0)
932
 
                ret = t_ret;
933
 
        if (realold != NULL)
934
 
                __os_free(dbenv, realold);
935
 
        if (realnew != NULL)
936
 
                __os_free(dbenv, realnew);
937
 
        if (realback != NULL)
938
 
                __os_free(dbenv, realback);
939
 
        if (back != NULL)
940
 
                __os_free(dbenv, back);
941
 
        return (ret);
942
 
}
943
 
 
944
 
/*
945
 
 * __fop_dbrename --
946
 
 *      Do the appropriate file locking and file system operations
947
 
 * to effect a dbrename in the absence of transactions (__fop_dummy
948
 
 * and the subsequent calls in __db_rename do the work for the
949
 
 * transactional case).
950
 
 *
951
 
 * PUBLIC: int __fop_dbrename __P((DB *, const char *, const char *));
952
 
 */
953
 
int
954
 
__fop_dbrename(dbp, old, new)
955
 
        DB *dbp;
956
 
        const char *old, *new;
957
 
{
958
 
        DB_ENV *dbenv;
959
 
        DB_LOCK elock;
960
 
        char *real_new, *real_old;
961
 
        int ret, tret;
962
 
 
963
 
        dbenv = dbp->dbenv;
964
 
        real_new = NULL;
965
 
        real_old = NULL;
966
 
        LOCK_INIT(elock);
967
 
 
968
 
        /* Find the real newname of the file. */
969
 
        if ((ret = __db_appname(dbenv,
970
 
            DB_APP_DATA, new, 0, NULL, &real_new)) != 0)
971
 
                goto err;
972
 
 
973
 
        /*
974
 
         * It is an error to rename a file over one that already exists,
975
 
         * as that wouldn't be transaction-safe.
976
 
         */
977
 
        GET_ENVLOCK(dbenv, dbp->lid, &elock);
978
 
        if (__os_exists(real_new, NULL) == 0) {
979
 
                ret = EEXIST;
980
 
                __db_err(dbenv, "rename: file %s exists", real_new);
981
 
                goto err;
982
 
        }
983
 
 
984
 
        if ((ret = __db_appname(dbenv,
985
 
            DB_APP_DATA, old, 0, NULL, &real_old)) != 0)
986
 
                goto err;
987
 
 
988
 
        ret = dbenv->memp_nameop(dbenv, dbp->fileid, new, real_old, real_new);
989
 
 
990
 
err:    if ((tret = REL_ENVLOCK(dbenv, &elock)) != 0 && ret == 0)
991
 
                ret = tret;
992
 
        if (real_old != NULL)
993
 
                __os_free(dbenv, real_old);
994
 
        if (real_new != NULL)
995
 
                __os_free(dbenv, real_new);
996
 
        return (ret);
997
 
}