📄 qam_files.c
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1999-2004 * Sleepycat Software. All rights reserved. * * $Id: qam_files.c,v 1.88 2004/10/21 14:54:42 bostic Exp $ */#include "db_config.h"#ifndef NO_SYSTEM_INCLUDES#include <sys/types.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#endif#include "db_int.h"#include "dbinc/db_page.h"#include "dbinc/db_shash.h"#include "dbinc/db_am.h"#include "dbinc/log.h"#include "dbinc/fop.h"#include "dbinc/mp.h"#include "dbinc/qam.h"#define QAM_EXNAME(Q, I, B, L) \ snprintf((B), (L), \ QUEUE_EXTENT, (Q)->dir, PATH_SEPARATOR[0], (Q)->name, (I))/* * __qam_fprobe -- calculate and open extent * * Calculate which extent the page is in, open and create if necessary. * * PUBLIC: int __qam_fprobe * PUBLIC: __P((DB *, db_pgno_t, void *, qam_probe_mode, u_int32_t)); */int__qam_fprobe(dbp, pgno, addrp, mode, flags) DB *dbp; db_pgno_t pgno; void *addrp; qam_probe_mode mode; u_int32_t flags;{ DB_ENV *dbenv; DB_MPOOLFILE *mpf; MPFARRAY *array; QUEUE *qp; u_int8_t fid[DB_FILE_ID_LEN]; u_int32_t extid, maxext, numext, offset, oldext, openflags; char buf[MAXPATHLEN]; int ftype, less, ret, t_ret; dbenv = dbp->dbenv; qp = (QUEUE *)dbp->q_internal; ret = 0; if (qp->page_ext == 0) { mpf = dbp->mpf; return (mode == QAM_PROBE_GET ? __memp_fget(mpf, &pgno, flags, addrp) : __memp_fput(mpf, addrp, flags)); } mpf = NULL; /* * Need to lock long enough to find the mpf or create the file. * The file cannot go away because we must have a record locked * in that file. */ MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); extid = QAM_PAGE_EXTENT(dbp, pgno); /* Array1 will always be in use if array2 is in use. */ array = &qp->array1; if (array->n_extent == 0) { /* Start with 4 extents */ array->n_extent = 4; array->low_extent = extid; numext = offset = oldext = 0; less = 0; goto alloc; } if (extid < array->low_extent) { less = 1; offset = array->low_extent - extid; } else { less = 0; offset = extid - array->low_extent; } if (qp->array2.n_extent != 0 && (extid >= qp->array2.low_extent ? offset > extid - qp->array2.low_extent : offset > qp->array2.low_extent - extid)) { array = &qp->array2; if (extid < array->low_extent) { less = 1; offset = array->low_extent - extid; } else { less = 0; offset = extid - array->low_extent; } } /* * Check to see if the requested extent is outside the range of * extents in the array. This is true by default if there are * no extents here yet. */ if (less == 1 || offset >= array->n_extent) { oldext = array->n_extent; numext = (array->hi_extent - array->low_extent) + 1; if (less == 1 && offset + numext <= array->n_extent) { /* * If we can fit this one into the existing array by * shifting the existing entries then we do not have * to allocate. */ memmove(&array->mpfarray[offset], array->mpfarray, numext * sizeof(array->mpfarray[0])); memset(array->mpfarray, 0, offset * sizeof(array->mpfarray[0])); offset = 0; } else if (less == 0 && offset == array->n_extent && mode != QAM_PROBE_MPF && array->mpfarray[0].pinref == 0) { /* * If this is at the end of the array and the file at * the beginning has a zero pin count we can close * the bottom extent and put this one at the end. * TODO: If this process is "slow" then it might be * appending but miss one or more extents. * We could check to see if all the extents * are unpinned and close them in the else * clause below. */ mpf = array->mpfarray[0].mpf; if (mpf != NULL && (ret = __memp_fclose(mpf, 0)) != 0) goto err; memmove(&array->mpfarray[0], &array->mpfarray[1], (array->n_extent - 1) * sizeof(array->mpfarray[0])); array->low_extent++; array->hi_extent++; offset--; array->mpfarray[offset].mpf = NULL; array->mpfarray[offset].pinref = 0; } else { /* * See if we have wrapped around the queue. * If it has then allocate the second array. * Otherwise just expand the one we are using. */ maxext = (u_int32_t) UINT32_MAX / (qp->page_ext * qp->rec_page); if (offset >= maxext/2) { array = &qp->array2; DB_ASSERT(array->n_extent == 0); oldext = 0; array->n_extent = 4; array->low_extent = extid; offset = 0; numext = 0; } else { /* * Increase the size to at least include * the new one and double it. */ array->n_extent += offset; array->n_extent <<= 2; }alloc: if ((ret = __os_realloc(dbenv, array->n_extent * sizeof(struct __qmpf), &array->mpfarray)) != 0) goto err; if (less == 1) { /* * Move the array up and put the new one * in the first slot. */ memmove(&array->mpfarray[offset], array->mpfarray, numext * sizeof(array->mpfarray[0])); memset(array->mpfarray, 0, offset * sizeof(array->mpfarray[0])); memset(&array->mpfarray[numext + offset], 0, (array->n_extent - (numext + offset)) * sizeof(array->mpfarray[0])); offset = 0; } else /* Clear the new part of the array. */ memset(&array->mpfarray[oldext], 0, (array->n_extent - oldext) * sizeof(array->mpfarray[0])); } } /* Update the low and hi range of saved extents. */ if (extid < array->low_extent) array->low_extent = extid; if (extid > array->hi_extent) array->hi_extent = extid; /* If the extent file is not yet open, open it. */ if (array->mpfarray[offset].mpf == NULL) { QAM_EXNAME(qp, extid, buf, sizeof(buf)); if ((ret = __memp_fcreate( dbenv, &array->mpfarray[offset].mpf)) != 0) goto err; mpf = array->mpfarray[offset].mpf; (void)__memp_set_lsn_offset(mpf, 0); (void)__memp_set_pgcookie(mpf, &qp->pgcookie); (void)__memp_get_ftype(dbp->mpf, &ftype); (void)__memp_set_ftype(mpf, ftype); /* Set up the fileid for this extent. */ __qam_exid(dbp, fid, extid); (void)__memp_set_fileid(mpf, fid); openflags = DB_EXTENT; if (LF_ISSET(DB_MPOOL_CREATE)) openflags |= DB_CREATE; if (F_ISSET(dbp, DB_AM_RDONLY)) openflags |= DB_RDONLY; if (F_ISSET(dbenv, DB_ENV_DIRECT_DB)) openflags |= DB_DIRECT; if ((ret = __memp_fopen( mpf, NULL, buf, openflags, qp->mode, dbp->pgsize)) != 0) { array->mpfarray[offset].mpf = NULL; (void)__memp_fclose(mpf, 0); goto err; } } /* * We have found the right file. Update its ref count * before dropping the dbp mutex so it does not go away. */ mpf = array->mpfarray[offset].mpf; if (mode == QAM_PROBE_GET) array->mpfarray[offset].pinref++; /* * If we may create the page, then we are writing, * the file may nolonger be empty after this operation * so we clear the UNLINK flag. */ if (LF_ISSET(DB_MPOOL_CREATE)) (void)__memp_set_flags(mpf, DB_MPOOL_UNLINK, 0);err: MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); if (ret == 0) { if (mode == QAM_PROBE_MPF) { *(DB_MPOOLFILE **)addrp = mpf; return (0); } pgno--; pgno %= qp->page_ext; if (mode == QAM_PROBE_GET) { if ((ret = __memp_fget(mpf, &pgno, flags, addrp)) == 0) return (ret); } else ret = __memp_fput(mpf, addrp, flags); MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); /* Recalculate because we dropped the lock. */ offset = extid - array->low_extent; DB_ASSERT(array->mpfarray[offset].pinref > 0); if (--array->mpfarray[offset].pinref == 0 && (mode == QAM_PROBE_GET || ret == 0)) { /* Check to see if this file will be unlinked. */ (void)__memp_get_flags(mpf, &flags); if (LF_ISSET(DB_MPOOL_UNLINK)) { array->mpfarray[offset].mpf = NULL; if ((t_ret = __memp_fclose(mpf, 0)) != 0 && ret == 0) ret = t_ret; } } MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); } return (ret);}/* * __qam_fclose -- close an extent. * * Calculate which extent the page is in and close it. * We assume the mpf entry is present. * * PUBLIC: int __qam_fclose __P((DB *, db_pgno_t)); */int__qam_fclose(dbp, pgnoaddr) DB *dbp; db_pgno_t pgnoaddr;{ DB_ENV *dbenv; DB_MPOOLFILE *mpf; MPFARRAY *array; QUEUE *qp; u_int32_t extid, offset; int ret; ret = 0; dbenv = dbp->dbenv; qp = (QUEUE *)dbp->q_internal; MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); extid = QAM_PAGE_EXTENT(dbp, pgnoaddr); array = &qp->array1; if (array->low_extent > extid || array->hi_extent < extid) array = &qp->array2; offset = extid - array->low_extent; DB_ASSERT(extid >= array->low_extent && offset < array->n_extent); /* If other threads are still using this file, leave it. */ if (array->mpfarray[offset].pinref != 0) goto done; mpf = array->mpfarray[offset].mpf; array->mpfarray[offset].mpf = NULL; ret = __memp_fclose(mpf, 0);done: MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); return (ret);}/* * __qam_fremove -- remove an extent. * * Calculate which extent the page is in and remove it. There is no way * to remove an extent without probing it first and seeing that is is empty * so we assume the mpf entry is present. * * PUBLIC: int __qam_fremove __P((DB *, db_pgno_t)); */int__qam_fremove(dbp, pgnoaddr) DB *dbp; db_pgno_t pgnoaddr;{ DB_ENV *dbenv; DB_MPOOLFILE *mpf; MPFARRAY *array; QUEUE *qp; u_int32_t extid, offset;#ifdef CONFIG_TEST char buf[MAXPATHLEN], *real_name;#endif int ret; qp = (QUEUE *)dbp->q_internal; dbenv = dbp->dbenv; ret = 0; MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); extid = QAM_PAGE_EXTENT(dbp, pgnoaddr); array = &qp->array1; if (array->low_extent > extid || array->hi_extent < extid) array = &qp->array2; offset = extid - array->low_extent; DB_ASSERT(extid >= array->low_extent && offset < array->n_extent);#ifdef CONFIG_TEST real_name = NULL; /* Find the real name of the file. */ QAM_EXNAME(qp, extid, buf, sizeof(buf)); if ((ret = __db_appname(dbenv, DB_APP_DATA, buf, 0, NULL, &real_name)) != 0) goto err;#endif /* * The log must be flushed before the file is deleted. We depend on * the log record of the last delete to recreate the file if we crash. */ if (LOGGING_ON(dbenv) && (ret = __log_flush(dbenv, NULL)) != 0) goto err; mpf = array->mpfarray[offset].mpf; (void)__memp_set_flags(mpf, DB_MPOOL_UNLINK, 1); /* Someone could be real slow, let them close it down. */ if (array->mpfarray[offset].pinref != 0) goto err; array->mpfarray[offset].mpf = NULL; if ((ret = __memp_fclose(mpf, 0)) != 0) goto err; /* * If the file is at the bottom of the array * shift things down and adjust the end points. */ if (offset == 0) { memmove(array->mpfarray, &array->mpfarray[1], (array->hi_extent - array->low_extent) * sizeof(array->mpfarray[0])); array->mpfarray[ array->hi_extent - array->low_extent].mpf = NULL; if (array->low_extent != array->hi_extent)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -