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

os_fid.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: os_fid.c,v 12.4 2005/10/14 15:33:08 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 #include <sys/stat.h>
00015 
00016 #include <stdlib.h>
00017 #include <string.h>
00018 #endif
00019 
00020 #include "db_int.h"
00021 
00022 /*
00023  * __os_fileid --
00024  *      Return a unique identifier for a file.  The structure
00025  * of a fileid is: ino(4) dev(4) time(4) pid(4) extra(4).
00026  * For real files, which have a backing inode and device, the first
00027  * 16 bytes are filled in and the extra bytes are left 0.  For
00028  * temporary files, the inode and device fields are left blank and
00029  * the extra four bytes are filled in with a random value.
00030  *
00031  * PUBLIC: int __os_fileid __P((DB_ENV *, const char *, int, u_int8_t *));
00032  */
00033 int
00034 __os_fileid(dbenv, fname, unique_okay, fidp)
00035         DB_ENV *dbenv;
00036         const char *fname;
00037         int unique_okay;
00038         u_int8_t *fidp;
00039 {
00040         pid_t pid;
00041         db_threadid_t tid;
00042         struct stat sb;
00043         size_t i;
00044         int ret;
00045         u_int32_t tmp;
00046         u_int8_t *p;
00047 
00048         /* Clear the buffer. */
00049         memset(fidp, 0, DB_FILE_ID_LEN);
00050 
00051         /* On POSIX/UNIX, use a dev/inode pair. */
00052 #ifdef HAVE_VXWORKS
00053         RETRY_CHK((stat((char *)fname, &sb)), ret);
00054 #else
00055         RETRY_CHK((stat(fname, &sb)), ret);
00056 #endif
00057         if (ret != 0) {
00058                 __db_err(dbenv, "%s: %s", fname, strerror(ret));
00059                 return (ret);
00060         }
00061 
00062         /*
00063          * !!!
00064          * Nothing is ever big enough -- on Sparc V9, st_ino, st_dev and the
00065          * time_t types are all 8 bytes.  As DB_FILE_ID_LEN is only 20 bytes,
00066          * we convert to a (potentially) smaller fixed-size type and use it.
00067          *
00068          * We don't worry about byte sexing or the actual variable sizes.
00069          *
00070          * When this routine is called from the DB access methods, it's only
00071          * called once -- whatever ID is generated when a database is created
00072          * is stored in the database file's metadata, and that is what is
00073          * saved in the mpool region's information to uniquely identify the
00074          * file.
00075          *
00076          * When called from the mpool layer this routine will be called each
00077          * time a new thread of control wants to share the file, which makes
00078          * things tougher.  As far as byte sexing goes, since the mpool region
00079          * lives on a single host, there's no issue of that -- the entire
00080          * region is byte sex dependent.  As far as variable sizes go, we make
00081          * the simplifying assumption that 32-bit and 64-bit processes will
00082          * get the same 32-bit values if we truncate any returned 64-bit value
00083          * to a 32-bit value.  When we're called from the mpool layer, though,
00084          * we need to be careful not to include anything that isn't
00085          * reproducible for a given file, such as the timestamp or serial
00086          * number.
00087          */
00088         tmp = (u_int32_t)sb.st_ino;
00089         for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
00090                 *fidp++ = *p++;
00091 
00092         tmp = (u_int32_t)sb.st_dev;
00093         for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
00094                 *fidp++ = *p++;
00095 
00096         if (unique_okay) {
00097                 static u_int32_t fid_serial = 0;
00098 
00099                 /* Add in 32-bits of (hopefully) unique number. */
00100                 __os_unique_id(dbenv, &tmp);
00101                 for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
00102                         *fidp++ = *p++;
00103 
00104                 /*
00105                  * Initialize/increment the serial number we use to help
00106                  * avoid fileid collisions.  Note we don't bother with
00107                  * locking; it's unpleasant to do from down in here, and
00108                  * if we race on this no real harm will be done, since the
00109                  * finished fileid has so many other components.
00110                  *
00111                  * We use the bottom 32-bits of the process ID, hoping they
00112                  * are more random than the top 32-bits (should we be on a
00113                  * machine with 64-bit process IDs).
00114                  *
00115                  * We increment by 100000 on each call as a simple way of
00116                  * randomizing; simply incrementing seems potentially less
00117                  * useful if pids are also simply incremented, since this
00118                  * is process-local and we may be one of a set of processes
00119                  * starting up.  100000 pushes us out of pid space on most
00120                  * 32-bit platforms, and has few interesting properties in
00121                  * base 2.
00122                  */
00123                 if (fid_serial == 0) {
00124                         dbenv->thread_id(dbenv, &pid, &tid);
00125                         fid_serial = (u_int32_t)pid;
00126                 } else
00127                         fid_serial += 100000;
00128 
00129                 for (p =
00130                     (u_int8_t *)&fid_serial, i = sizeof(u_int32_t); i > 0; --i)
00131                         *fidp++ = *p++;
00132         }
00133 
00134         return (0);
00135 }

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