diff options
Diffstat (limited to 'src/mp/mp_fopen.c')
-rw-r--r-- | src/mp/mp_fopen.c | 79 |
1 files changed, 63 insertions, 16 deletions
diff --git a/src/mp/mp_fopen.c b/src/mp/mp_fopen.c index ef7f886a..dbe7b9c8 100644 --- a/src/mp/mp_fopen.c +++ b/src/mp/mp_fopen.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ @@ -89,8 +89,9 @@ __memp_fopen_pp(dbmfp, path, flags, mode, pagesize) * Generate the number of user opens. If there is no backing file * there is an extra open count to keep the in memory db around. */ -#define MFP_OPEN_CNT(mfp) ((mfp)->mpf_cnt - ((mfp)->neutral_cnt + \ +#define MFP_OPEN_CNT(mfp) ((mfp)->mpf_cnt - ((mfp)->neutral_cnt + \ (u_int32_t)(mfp)->no_backing_file)) +#define MP_IOINFO_RETRIES 5 /* * __memp_fopen -- * DB_MPOOLFILE->open. @@ -118,7 +119,7 @@ __memp_fopen(dbmfp, mfp, path, dirp, flags, mode, pgsize) size_t maxmap; db_pgno_t last_pgno; u_int32_t bucket, mbytes, bytes, oflags, pagesize; - int refinc, ret, isdir; + int isdir, refinc, ret, tries; char *rpath; /* If this handle is already open, return. */ @@ -249,7 +250,7 @@ __memp_fopen(dbmfp, mfp, path, dirp, flags, mode, pgsize) if (MFP_OPEN_CNT(mfp) > 0 && atomic_read(&mfp->multiversion) == 0) { mvcc_err: __db_errx(env, DB_STR("3041", -"DB_MULTIVERSION cannot be specified on a database file which is already open")); +"DB_MULTIVERSION cannot be specified on a database file that is already open")); ret = EINVAL; goto err; } @@ -399,11 +400,44 @@ mvcc_err: __db_errx(env, DB_STR("3041", if (LF_ISSET(DB_ODDFILESIZE)) bytes -= (u_int32_t)(bytes % pagesize); else { - __db_errx(env, DB_STR_A("3037", - "%s: file size not a multiple of the pagesize", "%s"), - rpath); - ret = EINVAL; - goto err; + /* + * If the file size is not a multiple of the + * pagesize, it is likely because the ioinfo + * call is racing with a write that is extending + * the file. Many file systems will extend + * in fs block size units, and if the pagesize + * is larger than that, we can briefly see a + * file size that is not a multiple of pagesize. + * + * Yield the processor to allow that to finish + * and try again a few times. + */ + tries = 0; + STAT((mp->stat.st_oddfsize_detect++)); + while (tries < MP_IOINFO_RETRIES) { + if ((ret = __os_ioinfo(env, rpath, + dbmfp->fhp, &mbytes, &bytes, + NULL)) != 0) { + __db_err(env, ret, "%s", rpath); + goto err; + } + if (bytes % pagesize != 0) { + __os_yield(env, 0, 50000); + tries++; + } else { + STAT(( + mp->stat.st_oddfsize_resolve++)); + break; + } + } + if (tries == MP_IOINFO_RETRIES) { + __db_errx(env, DB_STR_A("3043", + "%s: file size (%lu %lu) not a multiple of the pagesize %lu", + "%s %lu %lu %lu"), + rpath, (u_long)mbytes, (u_long)bytes, (u_long)pagesize); + ret = EINVAL; + goto err; + } } } @@ -786,13 +820,7 @@ __memp_mpf_alloc(dbmp, dbmfp, path, pagesize, flags, retmfp) mfp->lsn_off = dbmfp->lsn_offset; mfp->clear_len = dbmfp->clear_len; mfp->priority = dbmfp->priority; - if (dbmfp->gbytes != 0 || dbmfp->bytes != 0) { - mfp->maxpgno = (db_pgno_t) - (dbmfp->gbytes * (GIGABYTE / mfp->pagesize)); - mfp->maxpgno += (db_pgno_t) - ((dbmfp->bytes + mfp->pagesize - 1) / - mfp->pagesize); - } + __memp_set_maxpgno(mfp, dbmfp->gbytes, dbmfp->bytes); if (FLD_ISSET(dbmfp->config_flags, DB_MPOOL_NOFILE)) mfp->no_backing_file = 1; if (FLD_ISSET(dbmfp->config_flags, DB_MPOOL_UNLINK)) @@ -1019,6 +1047,7 @@ __memp_fclose(dbmfp, flags) ret = t_ret; __os_free(env, rpath); } + mfp->unlink_on_close = 0; } if (MFP_OPEN_CNT(mfp) == 0) { F_CLR(mfp, MP_NOT_DURABLE); @@ -1068,6 +1097,7 @@ __memp_mf_discard(dbmp, mfp, hp_locked) DB_MPOOL_STAT *sp; #endif MPOOL *mp; + char *rpath; int need_sync, ret, t_ret; env = dbmp->env; @@ -1095,6 +1125,23 @@ __memp_mf_discard(dbmp, mfp, hp_locked) */ mfp->deadfile = 1; + /* We should unlink the file if necessary. */ + if (mfp->block_cnt == 0 && mfp->mpf_cnt == 0 && mfp->unlink_on_close && + !F_ISSET(mfp, MP_TEMP) && !mfp->no_backing_file) { + if ((t_ret = __db_appname(env, DB_APP_DATA, + R_ADDR(dbmp->reginfo, mfp->path_off), NULL, + &rpath)) != 0 && ret == 0) + ret = t_ret; + if (t_ret == 0) { + if ((t_ret = __os_unlink( + dbmp->env, rpath, 0)) != 0 && ret == 0) + ret = t_ret; + __os_free(env, rpath); + } + mfp->unlink_on_close = 0; + need_sync = 0; + } + /* Discard the mutex we're holding and return it too the pool. */ MUTEX_UNLOCK(env, mfp->mutex); if ((t_ret = __mutex_free(env, &mfp->mutex)) != 0 && ret == 0) |