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 }