--- db2/os/os_fid.c.db_fileid-64bit-fix 1998-06-09 11:04:45.000000000 -0400 +++ db2/os/os_fid.c 2002-11-23 03:56:38.000000000 -0500 @@ -17,12 +17,17 @@ static const char sccsid[] = "@(#)os_fid #include <errno.h> #include <string.h> +#include <unistd.h> +#include <sys/time.h> #include <time.h> #endif #include "db_int.h" #include "common_ext.h" +#define SERIAL_INIT 0 +static u_int32_t fid_serial = SERIAL_INIT; + /* * __db_fileid -- * Return a unique identifier for a file. @@ -38,39 +43,85 @@ __db_fileid(dbenv, fname, timestamp, fid { struct stat sb; size_t i; - time_t now; + int ret; + u_int32_t tmp; u_int8_t *p; /* Clear the buffer. */ memset(fidp, 0, DB_FILE_ID_LEN); - /* Check for the unthinkable. */ - if (sizeof(sb.st_ino) + - sizeof(sb.st_dev) + sizeof(time_t) > DB_FILE_ID_LEN) - return (EINVAL); - - /* On UNIX, use a dev/inode pair. */ if (stat(fname, &sb)) { __db_err(dbenv, "%s: %s", fname, strerror(errno)); return (errno); } /* - * Use the inode first and in reverse order, hopefully putting the - * distinguishing information early in the string. + * Initialize/increment the serial number we use to help avoid + * fileid collisions. Note that we don't bother with locking; + * it's unpleasant to do from down in here, and if we race on + * this no real harm will be done, since the finished fileid + * has so many other components. + * + * We increment by 100000 on each call as a simple way of + * randomizing; simply incrementing seems potentially less useful + * if pids are also simply incremented, since this is process-local + * and we may be one of a set of processes starting up. 100000 + * pushes us out of pid space on most platforms, and has few + * interesting properties in base 2. + */ + if (fid_serial == SERIAL_INIT) + fid_serial = (u_int32_t)getpid(); + else + fid_serial += 100000; + + /* + * !!! + * Nothing is ever big enough -- on Sparc V9, st_ino, st_dev and the + * time_t types are all 8 bytes. As DB_FILE_ID_LEN is only 20 bytes, + * we convert to a (potentially) smaller fixed-size type and use it. + * + * We don't worry about byte sexing or the actual variable sizes. + * + * When this routine is called from the DB access methods, it's only + * called once -- whatever ID is generated when a database is created + * is stored in the database file's metadata, and that is what is + * saved in the mpool region's information to uniquely identify the + * file. + * + * When called from the mpool layer this routine will be called each + * time a new thread of control wants to share the file, which makes + * things tougher. As far as byte sexing goes, since the mpool region + * lives on a single host, there's no issue of that -- the entire + * region is byte sex dependent. As far as variable sizes go, we make + * the simplifying assumption that 32-bit and 64-bit processes will + * get the same 32-bit values if we truncate any returned 64-bit value + * to a 32-bit value. When we're called from the mpool layer, though, + * we need to be careful not to include anything that isn't + * reproducible for a given file, such as the timestamp or serial + * number. */ - for (p = (u_int8_t *)&sb.st_ino + - sizeof(sb.st_ino), i = 0; i < sizeof(sb.st_ino); ++i) - *fidp++ = *--p; - for (p = (u_int8_t *)&sb.st_dev + - sizeof(sb.st_dev), i = 0; i < sizeof(sb.st_dev); ++i) - *fidp++ = *--p; + tmp = (u_int32_t)sb.st_ino; + for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; + + tmp = (u_int32_t)sb.st_dev; + for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; if (timestamp) { - (void)time(&now); - for (p = (u_int8_t *)&now + - sizeof(now), i = 0; i < sizeof(now); ++i) - *fidp++ = *--p; + /* + * We want the number of seconds, not the high-order 0 bits, + * so convert the returned time_t to a (potentially) smaller + * fixed-size type. + */ + tmp = (u_int32_t)time(NULL); + for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; + + for (p = (u_int8_t *)&fid_serial, i = sizeof(u_int32_t); + i > 0; --i) + *fidp++ = *p++; } + return (0); }