Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

qam_files.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1999-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: qam_files.c,v 12.6 2005/10/20 18:57:12 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 #include <stdlib.h>
00015 
00016 #include <string.h>
00017 #include <ctype.h>
00018 #endif
00019 
00020 #include "db_int.h"
00021 #include "dbinc/db_page.h"
00022 #include "dbinc/db_shash.h"
00023 #include "dbinc/db_am.h"
00024 #include "dbinc/log.h"
00025 #include "dbinc/fop.h"
00026 #include "dbinc/mp.h"
00027 #include "dbinc/qam.h"
00028 
00029 #define QAM_EXNAME(Q, I, B, L)                                          \
00030         snprintf((B), (L),                                              \
00031             QUEUE_EXTENT, (Q)->dir, PATH_SEPARATOR[0], (Q)->name, (I))
00032 
00033 /*
00034  * __qam_fprobe -- calculate and open extent
00035  *
00036  * Calculate which extent the page is in, open and create if necessary.
00037  *
00038  * PUBLIC: int __qam_fprobe
00039  * PUBLIC:         __P((DB *, db_pgno_t, void *, qam_probe_mode, u_int32_t));
00040  */
00041 int
00042 __qam_fprobe(dbp, pgno, addrp, mode, flags)
00043         DB *dbp;
00044         db_pgno_t pgno;
00045         void *addrp;
00046         qam_probe_mode mode;
00047         u_int32_t flags;
00048 {
00049         DB_ENV *dbenv;
00050         DB_MPOOLFILE *mpf;
00051         MPFARRAY *array;
00052         QUEUE *qp;
00053         u_int8_t fid[DB_FILE_ID_LEN];
00054         u_int32_t i, extid, maxext, numext, lflags, offset, oldext, openflags;
00055         char buf[MAXPATHLEN];
00056         int ftype, less, ret, t_ret;
00057 
00058         dbenv = dbp->dbenv;
00059         qp = (QUEUE *)dbp->q_internal;
00060         ret = 0;
00061 
00062         if (qp->page_ext == 0) {
00063                 mpf = dbp->mpf;
00064                 return (mode == QAM_PROBE_GET ?
00065                     __memp_fget(mpf, &pgno, flags, addrp) :
00066                     __memp_fput(mpf, addrp, flags));
00067         }
00068 
00069         mpf = NULL;
00070 
00071         /*
00072          * Need to lock long enough to find the mpf or create the file.
00073          * The file cannot go away because we must have a record locked
00074          * in that file.
00075          */
00076         MUTEX_LOCK(dbenv, dbp->mutex);
00077         extid = QAM_PAGE_EXTENT(dbp, pgno);
00078 
00079         /* Array1 will always be in use if array2 is in use. */
00080         array = &qp->array1;
00081         if (array->n_extent == 0) {
00082                 /* Start with 4 extents */
00083                 array->n_extent = 4;
00084                 array->low_extent = extid;
00085                 numext = offset = oldext = 0;
00086                 less = 0;
00087                 goto alloc;
00088         }
00089 
00090 retry:
00091         if (extid < array->low_extent) {
00092                 less = 1;
00093                 offset = array->low_extent - extid;
00094         } else {
00095                 less = 0;
00096                 offset = extid - array->low_extent;
00097         }
00098         if (qp->array2.n_extent != 0 &&
00099             (extid >= qp->array2.low_extent ?
00100             offset > extid - qp->array2.low_extent :
00101             offset > qp->array2.low_extent - extid)) {
00102                 array = &qp->array2;
00103                 if (extid < array->low_extent) {
00104                         less = 1;
00105                         offset = array->low_extent - extid;
00106                 } else {
00107                         less = 0;
00108                         offset = extid - array->low_extent;
00109                 }
00110         }
00111 
00112         /*
00113          * Check to see if the requested extent is outside the range of
00114          * extents in the array.  This is true by default if there are
00115          * no extents here yet.
00116          */
00117         if (less == 1 || offset >= array->n_extent) {
00118                 oldext = array->n_extent;
00119                 numext = (array->hi_extent - array->low_extent) + 1;
00120                 if (less == 1 && offset + numext <= array->n_extent) {
00121                         /*
00122                          * If we can fit this one into the existing array by
00123                          * shifting the existing entries then we do not have
00124                          * to allocate.
00125                          */
00126                         memmove(&array->mpfarray[offset],
00127                             array->mpfarray, numext
00128                             * sizeof(array->mpfarray[0]));
00129                         memset(array->mpfarray, 0, offset
00130                             * sizeof(array->mpfarray[0]));
00131                         offset = 0;
00132                 } else if (less == 0 && offset == array->n_extent &&
00133                     mode != QAM_PROBE_MPF && array->mpfarray[0].pinref == 0) {
00134                         /*
00135                          * If this is at the end of the array and the file at
00136                          * the beginning has a zero pin count we can close
00137                          * the bottom extent and put this one at the end.
00138                          */
00139                         mpf = array->mpfarray[0].mpf;
00140                         if (mpf != NULL && (ret = __memp_fclose(mpf, 0)) != 0)
00141                                 goto err;
00142                         memmove(&array->mpfarray[0], &array->mpfarray[1],
00143                             (array->n_extent - 1) * sizeof(array->mpfarray[0]));
00144                         array->low_extent++;
00145                         array->hi_extent++;
00146                         offset--;
00147                         array->mpfarray[offset].mpf = NULL;
00148                         array->mpfarray[offset].pinref = 0;
00149                 } else {
00150                         /*
00151                          * See if we have wrapped around the queue.
00152                          * If it has then allocate the second array.
00153                          * Otherwise just expand the one we are using.
00154                          */
00155                         maxext = (u_int32_t) UINT32_MAX
00156                             / (qp->page_ext * qp->rec_page);
00157                         if (offset >= maxext/2) {
00158                                 array = &qp->array2;
00159                                 DB_ASSERT(array->n_extent == 0);
00160                                 oldext = 0;
00161                                 array->n_extent = 4;
00162                                 array->low_extent = extid;
00163                                 offset = 0;
00164                                 numext = 0;
00165                         } else if (array->mpfarray[0].pinref == 0) {
00166                                 /*
00167                                  * Check to see if there are extents marked
00168                                  * for deletion at the beginning of the cache.
00169                                  * If so close them so they will go away.
00170                                  */
00171                                 for (i = 0; i < array->n_extent; i++) {
00172                                         if (array->mpfarray[i].pinref != 0)
00173                                                 break;
00174                                         mpf = array->mpfarray[i].mpf;
00175                                         if (mpf == NULL)
00176                                                 continue;
00177                                         (void)__memp_get_flags(mpf, &lflags);
00178                                         if (!FLD_ISSET(lflags, DB_MPOOL_UNLINK))
00179                                                 break;
00180 
00181                                         array->mpfarray[i].mpf = NULL;
00182                                         if ((ret = __memp_fclose(mpf, 0)) != 0)
00183                                                 goto err;
00184                                 }
00185                                 if (i == 0)
00186                                         goto increase;
00187                                 memmove(&array->mpfarray[0],
00188                                      &array->mpfarray[i],
00189                                     (array->n_extent - i) *
00190                                     sizeof(array->mpfarray[0]));
00191                                 memset(&array->mpfarray[array->n_extent - i],
00192                                      '\0', i * sizeof(array->mpfarray[0]));
00193                                 array->low_extent += i;
00194                                 array->hi_extent += i;
00195                                 goto retry;
00196                         } else {
00197                                 /*
00198                                  * Increase the size to at least include
00199                                  * the new one and double it.
00200                                  */
00201 increase:                       array->n_extent += offset;
00202                                 array->n_extent <<= 2;
00203                         }
00204 alloc:                  if ((ret = __os_realloc(dbenv,
00205                             array->n_extent * sizeof(struct __qmpf),
00206                             &array->mpfarray)) != 0)
00207                                 goto err;
00208 
00209                         if (less == 1) {
00210                                 /*
00211                                  * Move the array up and put the new one
00212                                  * in the first slot.
00213                                  */
00214                                 memmove(&array->mpfarray[offset],
00215                                     array->mpfarray,
00216                                     numext * sizeof(array->mpfarray[0]));
00217                                 memset(array->mpfarray, 0,
00218                                     offset * sizeof(array->mpfarray[0]));
00219                                 memset(&array->mpfarray[numext + offset], 0,
00220                                     (array->n_extent - (numext + offset))
00221                                     * sizeof(array->mpfarray[0]));
00222                                 offset = 0;
00223                         }
00224                         else
00225                                 /* Clear the new part of the array. */
00226                                 memset(&array->mpfarray[oldext], 0,
00227                                     (array->n_extent - oldext) *
00228                                     sizeof(array->mpfarray[0]));
00229                 }
00230         }
00231 
00232         /* Update the low and hi range of saved extents. */
00233         if (extid < array->low_extent)
00234                 array->low_extent = extid;
00235         if (extid > array->hi_extent)
00236                 array->hi_extent = extid;
00237 
00238         /* If the extent file is not yet open, open it. */
00239         if (array->mpfarray[offset].mpf == NULL) {
00240                 QAM_EXNAME(qp, extid, buf, sizeof(buf));
00241                 if ((ret = __memp_fcreate(
00242                     dbenv, &array->mpfarray[offset].mpf)) != 0)
00243                         goto err;
00244                 mpf = array->mpfarray[offset].mpf;
00245                 (void)__memp_set_lsn_offset(mpf, 0);
00246                 (void)__memp_set_pgcookie(mpf, &qp->pgcookie);
00247                 (void)__memp_get_ftype(dbp->mpf, &ftype);
00248                 (void)__memp_set_ftype(mpf, ftype);
00249                 (void)__memp_set_clear_len(mpf, dbp->pgsize);
00250 
00251                 /* Set up the fileid for this extent. */
00252                 __qam_exid(dbp, fid, extid);
00253                 (void)__memp_set_fileid(mpf, fid);
00254                 openflags = DB_EXTENT;
00255                 if (LF_ISSET(DB_MPOOL_CREATE))
00256                         openflags |= DB_CREATE;
00257                 if (F_ISSET(dbp, DB_AM_RDONLY))
00258                         openflags |= DB_RDONLY;
00259                 if (F_ISSET(dbenv, DB_ENV_DIRECT_DB))
00260                         openflags |= DB_DIRECT;
00261                 if ((ret = __memp_fopen(
00262                     mpf, NULL, buf, openflags, qp->mode, dbp->pgsize)) != 0) {
00263                         array->mpfarray[offset].mpf = NULL;
00264                         (void)__memp_fclose(mpf, 0);
00265                         goto err;
00266                 }
00267         }
00268 
00269         /*
00270          * We have found the right file.  Update its ref count
00271          * before dropping the dbp mutex so it does not go away.
00272          */
00273         mpf = array->mpfarray[offset].mpf;
00274         if (mode == QAM_PROBE_GET)
00275                 array->mpfarray[offset].pinref++;
00276 
00277         /*
00278          * If we may create the page, then we are writing,
00279          * the file may nolonger be empty after this operation
00280          * so we clear the UNLINK flag.
00281          */
00282         if (LF_ISSET(DB_MPOOL_CREATE))
00283                 (void)__memp_set_flags(mpf, DB_MPOOL_UNLINK, 0);
00284 
00285 err:
00286         MUTEX_UNLOCK(dbenv, dbp->mutex);
00287 
00288         if (ret == 0) {
00289                 if (mode == QAM_PROBE_MPF) {
00290                         *(DB_MPOOLFILE **)addrp = mpf;
00291                         return (0);
00292                 }
00293                 pgno--;
00294                 pgno %= qp->page_ext;
00295                 if (mode == QAM_PROBE_GET) {
00296                         if ((ret = __memp_fget(mpf, &pgno, flags, addrp)) == 0)
00297                                 return (ret);
00298                 } else
00299                         ret = __memp_fput(mpf, addrp, flags);
00300 
00301                 MUTEX_LOCK(dbenv, dbp->mutex);
00302                 /* Recalculate because we dropped the lock. */
00303                 offset = extid - array->low_extent;
00304                 DB_ASSERT(array->mpfarray[offset].pinref > 0);
00305                 if (--array->mpfarray[offset].pinref == 0 &&
00306                     (mode == QAM_PROBE_GET || ret == 0)) {
00307                         /* Check to see if this file will be unlinked. */
00308                         (void)__memp_get_flags(mpf, &flags);
00309                         if (LF_ISSET(DB_MPOOL_UNLINK)) {
00310                                 array->mpfarray[offset].mpf = NULL;
00311                                 if ((t_ret =
00312                                     __memp_fclose(mpf, 0)) != 0 && ret == 0)
00313                                         ret = t_ret;
00314                         }
00315                 }
00316                 MUTEX_UNLOCK(dbenv, dbp->mutex);
00317         }
00318         return (ret);
00319 }
00320 
00321 /*
00322  * __qam_fclose -- close an extent.
00323  *
00324  * Calculate which extent the page is in and close it.
00325  * We assume the mpf entry is present.
00326  *
00327  * PUBLIC: int __qam_fclose __P((DB *, db_pgno_t));
00328  */
00329 int
00330 __qam_fclose(dbp, pgnoaddr)
00331         DB *dbp;
00332         db_pgno_t pgnoaddr;
00333 {
00334         DB_ENV *dbenv;
00335         DB_MPOOLFILE *mpf;
00336         MPFARRAY *array;
00337         QUEUE *qp;
00338         u_int32_t extid, offset;
00339         int ret;
00340 
00341         ret = 0;
00342         dbenv = dbp->dbenv;
00343         qp = (QUEUE *)dbp->q_internal;
00344 
00345         MUTEX_LOCK(dbenv, dbp->mutex);
00346 
00347         extid = QAM_PAGE_EXTENT(dbp, pgnoaddr);
00348         array = &qp->array1;
00349         if (array->low_extent > extid || array->hi_extent < extid)
00350                 array = &qp->array2;
00351         offset = extid - array->low_extent;
00352 
00353         DB_ASSERT(extid >= array->low_extent && offset < array->n_extent);
00354 
00355         /* If other threads are still using this file, leave it. */
00356         if (array->mpfarray[offset].pinref != 0)
00357                 goto done;
00358 
00359         mpf = array->mpfarray[offset].mpf;
00360         array->mpfarray[offset].mpf = NULL;
00361         ret = __memp_fclose(mpf, 0);
00362 
00363 done:
00364         MUTEX_UNLOCK(dbenv, dbp->mutex);
00365         return (ret);
00366 }
00367 
00368 /*
00369  * __qam_fremove -- remove an extent.
00370  *
00371  * Calculate which extent the page is in and remove it.  There is no way
00372  * to remove an extent without probing it first and seeing that is is empty
00373  * so we assume the mpf entry is present.
00374  *
00375  * PUBLIC: int __qam_fremove __P((DB *, db_pgno_t));
00376  */
00377 int
00378 __qam_fremove(dbp, pgnoaddr)
00379         DB *dbp;
00380         db_pgno_t pgnoaddr;
00381 {
00382         DB_ENV *dbenv;
00383         DB_MPOOLFILE *mpf;
00384         MPFARRAY *array;
00385         QUEUE *qp;
00386         u_int32_t extid, offset;
00387 #ifdef CONFIG_TEST
00388         char buf[MAXPATHLEN], *real_name;
00389 #endif
00390         int ret;
00391 
00392         qp = (QUEUE *)dbp->q_internal;
00393         dbenv = dbp->dbenv;
00394         ret = 0;
00395 
00396         MUTEX_LOCK(dbenv, dbp->mutex);
00397 
00398         extid = QAM_PAGE_EXTENT(dbp, pgnoaddr);
00399         array = &qp->array1;
00400         if (array->low_extent > extid || array->hi_extent < extid)
00401                 array = &qp->array2;
00402         offset = extid - array->low_extent;
00403 
00404         DB_ASSERT(extid >= array->low_extent && offset < array->n_extent);
00405 
00406 #ifdef CONFIG_TEST
00407         real_name = NULL;
00408         /* Find the real name of the file. */
00409         QAM_EXNAME(qp, extid, buf, sizeof(buf));
00410         if ((ret = __db_appname(dbenv,
00411             DB_APP_DATA, buf, 0, NULL, &real_name)) != 0)
00412                 goto err;
00413 #endif
00414         /*
00415          * The log must be flushed before the file is deleted.  We depend on
00416          * the log record of the last delete to recreate the file if we crash.
00417          */
00418         if (LOGGING_ON(dbenv) && (ret = __log_flush(dbenv, NULL)) != 0)
00419                 goto err;
00420 
00421         mpf = array->mpfarray[offset].mpf;
00422         (void)__memp_set_flags(mpf, DB_MPOOL_UNLINK, 1);
00423         /* Someone could be real slow, let them close it down. */
00424         if (array->mpfarray[offset].pinref != 0)
00425                 goto err;
00426         array->mpfarray[offset].mpf = NULL;
00427         if ((ret = __memp_fclose(mpf, 0)) != 0)
00428                 goto err;
00429 
00430         /*
00431          * If the file is at the bottom of the array
00432          * shift things down and adjust the end points.
00433          */
00434         if (offset == 0) {
00435                 memmove(array->mpfarray, &array->mpfarray[1],
00436                     (array->hi_extent - array->low_extent)
00437                     * sizeof(array->mpfarray[0]));
00438                 array->mpfarray[
00439                     array->hi_extent - array->low_extent].mpf = NULL;
00440                 if (array->low_extent != array->hi_extent)
00441                         array->low_extent++;
00442         } else {
00443                 if (extid == array->hi_extent)
00444                         array->hi_extent--;
00445         }
00446 
00447 err:    MUTEX_UNLOCK(dbenv, dbp->mutex);
00448 
00449 #ifdef CONFIG_TEST
00450         if (real_name != NULL)
00451                 __os_free(dbenv, real_name);
00452 #endif
00453         return (ret);
00454 }
00455 
00456 /*
00457  * __qam_sync --
00458  *      Flush the database cache.
00459  *
00460  * PUBLIC: int __qam_sync __P((DB *));
00461  */
00462 int
00463 __qam_sync(dbp)
00464         DB *dbp;
00465 {
00466         DB_ENV *dbenv;
00467         DB_MPOOLFILE *mpf;
00468 
00469         dbenv = dbp->dbenv;
00470         mpf = dbp->mpf;
00471 
00472         /*
00473          * We need to flush all extent files.  There is no easy way to find
00474          * all the extents for this queue which are currently open. For now
00475          * just flush the whole cache.  An alternative would be to have a
00476          * call into the cache layer that would flush all of the queue extent
00477          * files it has open (there's a flag when we open a queue extent file,
00478          * so the cache layer can identify them).
00479          */
00480 
00481         if (((QUEUE *)dbp->q_internal)->page_ext == 0)
00482                 return (__memp_fsync(mpf));
00483         else
00484                 return (__memp_sync(dbenv, NULL));
00485 }
00486 
00487 /*
00488  * __qam_gen_filelist -- generate a list of extent files.
00489  *      Another thread may close the handle so this should only
00490  *      be used single threaded or with care.
00491  *
00492  * PUBLIC: int __qam_gen_filelist __P(( DB *, QUEUE_FILELIST **));
00493  */
00494 int
00495 __qam_gen_filelist(dbp, filelistp)
00496         DB *dbp;
00497         QUEUE_FILELIST **filelistp;
00498 {
00499         DB_ENV *dbenv;
00500         DB_MPOOLFILE *mpf;
00501         QUEUE *qp;
00502         QMETA *meta;
00503         size_t extent_cnt;
00504         db_recno_t i, current, first, stop, rec_extent;
00505         QUEUE_FILELIST *fp;
00506         int ret;
00507 
00508         dbenv = dbp->dbenv;
00509         mpf = dbp->mpf;
00510         qp = (QUEUE *)dbp->q_internal;
00511         *filelistp = NULL;
00512 
00513         if (qp->page_ext == 0)
00514                 return (0);
00515 
00516         /* This may happen during metapage recovery. */
00517         if (qp->name == NULL)
00518                 return (0);
00519 
00520         /* Find out the first and last record numbers in the database. */
00521         i = PGNO_BASE_MD;
00522         if ((ret = __memp_fget(mpf, &i, 0, &meta)) != 0)
00523                 return (ret);
00524 
00525         current = meta->cur_recno;
00526         first = meta->first_recno;
00527 
00528         if ((ret = __memp_fput(mpf, meta, 0)) != 0)
00529                 return (ret);
00530 
00531         /*
00532          * Allocate the extent array.  Calculate the worst case number of
00533          * pages and convert that to a count of extents.   The count of
00534          * extents has 3 or 4 extra slots:
00535          *   roundoff at first (e.g., current record in extent);
00536          *   roundoff at current (e.g., first record in extent);
00537          *   NULL termination; and
00538          *   UINT32_MAX wraparound (the last extent can be small).
00539          */
00540         rec_extent = qp->rec_page * qp->page_ext;
00541         if (current >= first)
00542                 extent_cnt = (current - first) / rec_extent + 3;
00543         else
00544                 extent_cnt =
00545                     (current + (UINT32_MAX - first)) / rec_extent + 4;
00546         if ((ret = __os_calloc(dbenv,
00547             extent_cnt, sizeof(QUEUE_FILELIST), filelistp)) != 0)
00548                 return (ret);
00549         fp = *filelistp;
00550 
00551 again:
00552         if (current >= first)
00553                 stop = current;
00554         else
00555                 stop = UINT32_MAX;
00556 
00557         /*
00558          * Make sure that first is at the same offset in the extent as stop.
00559          * This guarantees that the stop will be reached in the loop below,
00560          * even if it is the only record in its extent.  This calculation is
00561          * safe because first won't move out of its extent.
00562          */
00563         first -= first % rec_extent;
00564         first += stop % rec_extent;
00565 
00566         for (i = first; i >= first && i <= stop; i += rec_extent) {
00567                 if ((ret = __qam_fprobe(dbp, QAM_RECNO_PAGE(dbp, i), &fp->mpf,
00568                     QAM_PROBE_MPF, 0)) != 0) {
00569                         if (ret == ENOENT)
00570                                 continue;
00571                         return (ret);
00572                 }
00573                 fp->id = QAM_RECNO_EXTENT(dbp, i);
00574                 fp++;
00575                 DB_ASSERT((size_t)(fp - *filelistp) < extent_cnt);
00576         }
00577 
00578         if (current < first) {
00579                 first = 1;
00580                 goto again;
00581         }
00582 
00583         return (0);
00584 }
00585 
00586 /*
00587  * __qam_extent_names -- generate a list of extent files names.
00588  *
00589  * PUBLIC: int __qam_extent_names __P((DB_ENV *, char *, char ***));
00590  */
00591 int
00592 __qam_extent_names(dbenv, name, namelistp)
00593         DB_ENV *dbenv;
00594         char *name;
00595         char ***namelistp;
00596 {
00597         DB *dbp;
00598         QUEUE *qp;
00599         QUEUE_FILELIST *filelist, *fp;
00600         size_t len;
00601         int cnt, ret, t_ret;
00602         char buf[MAXPATHLEN], **cp, *freep;
00603 
00604         *namelistp = NULL;
00605         filelist = NULL;
00606         if ((ret = db_create(&dbp, dbenv, 0)) != 0)
00607                 return (ret);
00608         if ((ret = __db_open(dbp,
00609             NULL, name, NULL, DB_QUEUE, DB_RDONLY, 0, PGNO_BASE_MD)) != 0)
00610                 return (ret);
00611         qp = dbp->q_internal;
00612         if (qp->page_ext == 0)
00613                 goto done;
00614 
00615         if ((ret = __qam_gen_filelist(dbp, &filelist)) != 0)
00616                 goto done;
00617 
00618         if (filelist == NULL)
00619                 goto done;
00620 
00621         cnt = 0;
00622         for (fp = filelist; fp->mpf != NULL; fp++)
00623                 cnt++;
00624 
00625         /* QUEUE_EXTENT contains extra chars, but add 6 anyway for the int. */
00626         len = (size_t)cnt * (sizeof(**namelistp) +
00627             strlen(QUEUE_EXTENT) + strlen(qp->dir) + strlen(qp->name) + 6);
00628 
00629         if ((ret = __os_malloc(dbp->dbenv, len, namelistp)) != 0)
00630                 goto done;
00631         cp = *namelistp;
00632         freep = (char *)(cp + cnt + 1);
00633         for (fp = filelist; fp->mpf != NULL; fp++) {
00634                 QAM_EXNAME(qp, fp->id, buf, sizeof(buf));
00635                 len = strlen(buf);
00636                 *cp++ = freep;
00637                 (void)strcpy(freep, buf);
00638                 freep += len + 1;
00639         }
00640         *cp = NULL;
00641 
00642 done:
00643         if (filelist != NULL)
00644                 __os_free(dbp->dbenv, filelist);
00645         if ((t_ret = __db_close(dbp, NULL, DB_NOSYNC)) != 0 && ret == 0)
00646                 ret = t_ret;
00647 
00648         return (ret);
00649 }
00650 
00651 /*
00652  * __qam_exid --
00653  *      Generate a fileid for an extent based on the fileid of the main
00654  * file.  Since we do not log schema creates/deletes explicitly, the log
00655  * never captures the fileid of an extent file.  In order that masters and
00656  * replicas have the same fileids (so they can explicitly delete them), we
00657  * use computed fileids for the extent files of Queue files.
00658  *
00659  * An extent file id retains the low order 12 bytes of the file id and
00660  * overwrites the dev/inode fields, placing a 0 in the inode field, and
00661  * the extent number in the dev field.
00662  *
00663  * PUBLIC: void __qam_exid __P((DB *, u_int8_t *, u_int32_t));
00664  */
00665 void
00666 __qam_exid(dbp, fidp, exnum)
00667         DB *dbp;
00668         u_int8_t *fidp;
00669         u_int32_t exnum;
00670 {
00671         int i;
00672         u_int8_t *p;
00673 
00674         /* Copy the fileid from the master. */
00675         memcpy(fidp, dbp->fileid, DB_FILE_ID_LEN);
00676 
00677         /* The first four bytes are the inode or the FileIndexLow; 0 it. */
00678         for (i = sizeof(u_int32_t); i > 0; --i)
00679                 *fidp++ = 0;
00680 
00681         /* The next four bytes are the dev/FileIndexHigh; insert the exnum . */
00682         for (p = (u_int8_t *)&exnum, i = sizeof(u_int32_t); i > 0; --i)
00683                 *fidp++ = *p++;
00684 }
00685 
00686 /*
00687  * __qam_nameop --
00688  *      Remove or rename  extent files associated with a particular file.
00689  * This is to remove or rename (both in mpool and the file system) any
00690  * extent files associated with the given dbp.
00691  * This is either called from the QUEUE remove or rename methods or
00692  * when undoing a transaction that created the database.
00693  *
00694  * PUBLIC: int __qam_nameop __P((DB *, DB_TXN *, const char *, qam_name_op));
00695  */
00696 int __qam_nameop(dbp, txn, newname, op)
00697         DB *dbp;
00698         DB_TXN *txn;
00699         const char *newname;
00700         qam_name_op op;
00701 {
00702         DB_ENV *dbenv;
00703         QUEUE *qp;
00704         size_t exlen, fulllen, len;
00705         u_int8_t fid[DB_FILE_ID_LEN];
00706         u_int32_t exid;
00707         int cnt, i, ret, t_ret;
00708         char buf[MAXPATHLEN], nbuf[MAXPATHLEN], sepsave;
00709         char *endname, *endpath, *exname, *fullname, **names;
00710         char *ndir, *namep, *new, *cp;
00711 
00712         dbenv = dbp->dbenv;
00713         qp = (QUEUE *)dbp->q_internal;
00714         cnt = ret = t_ret = 0;
00715         namep = exname = fullname = NULL;
00716         names = NULL;
00717 
00718         /* If this isn't a queue with extents, we're done. */
00719         if (qp->page_ext == 0)
00720                 return (0);
00721 
00722         /*
00723          * Generate the list of all queue extents for this file (from the
00724          * file system) and then cycle through removing them and evicting
00725          * from mpool.  We have two modes of operation here.  If we are
00726          * undoing log operations, then do not write log records and try
00727          * to keep going even if we encounter failures in nameop.  If we
00728          * are in mainline code, then return as soon as we have a problem.
00729          * Memory allocation errors (__db_appname, __os_malloc) are always
00730          * considered failure.
00731          *
00732          * Set buf to : dir/__dbq.NAME.0 and fullname to HOME/dir/__dbq.NAME.0
00733          * or, in the case of an absolute path: /dir/__dbq.NAME.0
00734          */
00735         QAM_EXNAME(qp, 0, buf, sizeof(buf));
00736         if ((ret =
00737             __db_appname(dbenv, DB_APP_DATA, buf, 0, NULL, &fullname)) != 0)
00738                 return (ret);
00739 
00740         /* We should always have a path separator here. */
00741         if ((endpath = __db_rpath(fullname)) == NULL) {
00742                 ret = EINVAL;
00743                 goto err;
00744         }
00745         sepsave = *endpath;
00746         *endpath = '\0';
00747 
00748         /*
00749          * Get the list of all names in the directory and restore the
00750          * path separator.
00751          */
00752         if ((ret = __os_dirlist(dbenv, fullname, &names, &cnt)) != 0)
00753                 goto err;
00754         *endpath = sepsave;
00755 
00756         /* If there aren't any names, don't allocate any space. */
00757         if (cnt == 0)
00758                 goto err;
00759 
00760         /*
00761          * Now, make endpath reference the queue extent names upon which
00762          * we can match.  Then we set the end of the path to be the
00763          * beginning of the extent number, and we can compare the bytes
00764          * between endpath and endname (__dbq.NAME.).
00765          */
00766         endpath++;
00767         endname = strrchr(endpath, '.');
00768         if (endname == NULL) {
00769                 ret = EINVAL;
00770                 goto err;
00771         }
00772         ++endname;
00773         *endname = '\0';
00774         len = strlen(endpath);
00775         fulllen = strlen(fullname);
00776 
00777         /* Allocate space for a full extent name.  */
00778         exlen = fulllen + 20;
00779         if ((ret = __os_malloc(dbenv, exlen, &exname)) != 0)
00780                 goto err;
00781 
00782         ndir = new = NULL;
00783         if (newname != NULL) {
00784                 if ((ret = __os_strdup(dbenv, newname, &namep)) != 0)
00785                         goto err;
00786                 ndir = namep;
00787                 if ((new = __db_rpath(namep)) != NULL)
00788                         *new++ = '\0';
00789                 else {
00790                         new = namep;
00791                         ndir = PATH_DOT;
00792                 }
00793         }
00794         for (i = 0; i < cnt; i++) {
00795                 /* Check if this is a queue extent file. */
00796                 if (strncmp(names[i], endpath, len) != 0)
00797                         continue;
00798                 /* Make sure we have all numbers. foo.db vs. foo.db.0. */
00799                 for (cp = &names[i][len]; *cp != '\0'; cp++)
00800                         if (!isdigit(*cp))
00801                                 break;
00802                 if (*cp != '\0')
00803                         continue;
00804 
00805                 /*
00806                  * We have a queue extent file.  We need to generate its
00807                  * name and its fileid.
00808                  */
00809                 exid = (u_int32_t)strtoul(names[i] + len, NULL, 10);
00810                 __qam_exid(dbp, fid, exid);
00811 
00812                 switch (op) {
00813                 case QAM_NAME_DISCARD:
00814                         snprintf(exname, exlen,
00815                              "%s%s", fullname, names[i] + len);
00816                         if ((t_ret = __memp_nameop(dbenv,
00817                             fid, NULL, exname, NULL,
00818                             F_ISSET(dbp, DB_AM_INMEM))) != 0 && ret == 0)
00819                                 ret = t_ret;
00820                         break;
00821 
00822                 case QAM_NAME_RENAME:
00823                         snprintf(nbuf, sizeof(nbuf), QUEUE_EXTENT,
00824                              ndir, PATH_SEPARATOR[0], new, exid);
00825                         QAM_EXNAME(qp, exid, buf, sizeof(buf));
00826                         if ((ret = __fop_rename(dbenv,
00827                             txn, buf, nbuf, fid, DB_APP_DATA,
00828                             F_ISSET(dbp, DB_AM_NOT_DURABLE) ?
00829                             DB_LOG_NOT_DURABLE : 0)) != 0)
00830                                 goto err;
00831                         break;
00832 
00833                 case QAM_NAME_REMOVE:
00834                         QAM_EXNAME(qp, exid, buf, sizeof(buf));
00835                         if ((ret = __fop_remove(dbenv, txn, fid, buf,
00836                             DB_APP_DATA, F_ISSET(dbp, DB_AM_NOT_DURABLE) ?
00837                             DB_LOG_NOT_DURABLE : 0)) != 0)
00838                                 goto err;
00839                         break;
00840                 }
00841         }
00842 
00843 err:    if (fullname != NULL)
00844                 __os_free(dbenv, fullname);
00845         if (exname != NULL)
00846                 __os_free(dbenv, exname);
00847         if (namep != NULL)
00848                 __os_free(dbenv, namep);
00849         if (names != NULL)
00850                 __os_dirfree(dbenv, names, cnt);
00851         return (ret);
00852 }

Generated on Sun Dec 25 12:14:44 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2