When using the OSSP UUID library, cache its uuid_t state object.
The original coding in contrib/uuid-ossp created and destroyed a uuid_t object (or, in some cases, even two of them) each time it was called. This is not the intended usage: you're supposed to keep the uuid_t object around so that the library can cache its state across uses. (Other UUID libraries seem to keep equivalent state behind-the-scenes in static variables, but OSSP chose differently.) Aside from being quite inefficient, creating a new uuid_t loses knowledge of the previously generated UUID, which in theory could result in duplicate V1-style UUIDs being created on sufficiently fast machines. On at least some platforms, creating a new uuid_t also draws some entropy from /dev/urandom, leaving less for the rest of the system. This seems sufficiently unpleasant to justify back-patching this change.
This commit is contained in:
parent
25dd07e0f6
commit
c941aed96b
1 changed files with 45 additions and 31 deletions
|
@ -141,6 +141,42 @@ pguuid_complain(uuid_rc_t rc)
|
||||||
errmsg("OSSP uuid library failure: error code %d", rc)));
|
errmsg("OSSP uuid library failure: error code %d", rc)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We create a uuid_t object just once per session and re-use it for all
|
||||||
|
* operations in this module. OSSP UUID caches the system MAC address and
|
||||||
|
* other state in this object. Reusing the object has a number of benefits:
|
||||||
|
* saving the cycles needed to fetch the system MAC address over and over,
|
||||||
|
* reducing the amount of entropy we draw from /dev/urandom, and providing a
|
||||||
|
* positive guarantee that successive generated V1-style UUIDs don't collide.
|
||||||
|
* (On a machine fast enough to generate multiple UUIDs per microsecond,
|
||||||
|
* or whatever the system's wall-clock resolution is, we'd otherwise risk
|
||||||
|
* collisions whenever random initialization of the uuid_t's clock sequence
|
||||||
|
* value chanced to produce duplicates.)
|
||||||
|
*
|
||||||
|
* However: when we're doing V3 or V5 UUID creation, uuid_make needs two
|
||||||
|
* uuid_t objects, one holding the namespace UUID and one for the result.
|
||||||
|
* It's unspecified whether it's safe to use the same uuid_t for both cases,
|
||||||
|
* so let's cache a second uuid_t for use as the namespace holder object.
|
||||||
|
*/
|
||||||
|
static uuid_t *
|
||||||
|
get_cached_uuid_t(int which)
|
||||||
|
{
|
||||||
|
static uuid_t *cached_uuid[2] = {NULL, NULL};
|
||||||
|
|
||||||
|
if (cached_uuid[which] == NULL)
|
||||||
|
{
|
||||||
|
uuid_rc_t rc;
|
||||||
|
|
||||||
|
rc = uuid_create(&cached_uuid[which]);
|
||||||
|
if (rc != UUID_RC_OK)
|
||||||
|
{
|
||||||
|
cached_uuid[which] = NULL;
|
||||||
|
pguuid_complain(rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cached_uuid[which];
|
||||||
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
uuid_to_string(const uuid_t *uuid)
|
uuid_to_string(const uuid_t *uuid)
|
||||||
{
|
{
|
||||||
|
@ -171,20 +207,14 @@ string_to_uuid(const char *str, uuid_t *uuid)
|
||||||
static Datum
|
static Datum
|
||||||
special_uuid_value(const char *name)
|
special_uuid_value(const char *name)
|
||||||
{
|
{
|
||||||
uuid_t *uuid;
|
uuid_t *uuid = get_cached_uuid_t(0);
|
||||||
char *str;
|
char *str;
|
||||||
uuid_rc_t rc;
|
uuid_rc_t rc;
|
||||||
|
|
||||||
rc = uuid_create(&uuid);
|
|
||||||
if (rc != UUID_RC_OK)
|
|
||||||
pguuid_complain(rc);
|
|
||||||
rc = uuid_load(uuid, name);
|
rc = uuid_load(uuid, name);
|
||||||
if (rc != UUID_RC_OK)
|
if (rc != UUID_RC_OK)
|
||||||
pguuid_complain(rc);
|
pguuid_complain(rc);
|
||||||
str = uuid_to_string(uuid);
|
str = uuid_to_string(uuid);
|
||||||
rc = uuid_destroy(uuid);
|
|
||||||
if (rc != UUID_RC_OK)
|
|
||||||
pguuid_complain(rc);
|
|
||||||
|
|
||||||
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
|
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
|
||||||
}
|
}
|
||||||
|
@ -193,20 +223,14 @@ special_uuid_value(const char *name)
|
||||||
static Datum
|
static Datum
|
||||||
uuid_generate_internal(int mode, const uuid_t *ns, const char *name, int len)
|
uuid_generate_internal(int mode, const uuid_t *ns, const char *name, int len)
|
||||||
{
|
{
|
||||||
uuid_t *uuid;
|
uuid_t *uuid = get_cached_uuid_t(0);
|
||||||
char *str;
|
char *str;
|
||||||
uuid_rc_t rc;
|
uuid_rc_t rc;
|
||||||
|
|
||||||
rc = uuid_create(&uuid);
|
|
||||||
if (rc != UUID_RC_OK)
|
|
||||||
pguuid_complain(rc);
|
|
||||||
rc = uuid_make(uuid, mode, ns, name);
|
rc = uuid_make(uuid, mode, ns, name);
|
||||||
if (rc != UUID_RC_OK)
|
if (rc != UUID_RC_OK)
|
||||||
pguuid_complain(rc);
|
pguuid_complain(rc);
|
||||||
str = uuid_to_string(uuid);
|
str = uuid_to_string(uuid);
|
||||||
rc = uuid_destroy(uuid);
|
|
||||||
if (rc != UUID_RC_OK)
|
|
||||||
pguuid_complain(rc);
|
|
||||||
|
|
||||||
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
|
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
|
||||||
}
|
}
|
||||||
|
@ -215,26 +239,16 @@ uuid_generate_internal(int mode, const uuid_t *ns, const char *name, int len)
|
||||||
static Datum
|
static Datum
|
||||||
uuid_generate_v35_internal(int mode, pg_uuid_t *ns, text *name)
|
uuid_generate_v35_internal(int mode, pg_uuid_t *ns, text *name)
|
||||||
{
|
{
|
||||||
uuid_t *ns_uuid;
|
uuid_t *ns_uuid = get_cached_uuid_t(1);
|
||||||
Datum result;
|
|
||||||
uuid_rc_t rc;
|
|
||||||
|
|
||||||
rc = uuid_create(&ns_uuid);
|
string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out,
|
||||||
if (rc != UUID_RC_OK)
|
UUIDPGetDatum(ns))),
|
||||||
pguuid_complain(rc);
|
|
||||||
string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out, UUIDPGetDatum(ns))),
|
|
||||||
ns_uuid);
|
ns_uuid);
|
||||||
|
|
||||||
result = uuid_generate_internal(mode,
|
return uuid_generate_internal(mode,
|
||||||
ns_uuid,
|
ns_uuid,
|
||||||
text_to_cstring(name),
|
text_to_cstring(name),
|
||||||
0);
|
0);
|
||||||
|
|
||||||
rc = uuid_destroy(ns_uuid);
|
|
||||||
if (rc != UUID_RC_OK)
|
|
||||||
pguuid_complain(rc);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* !HAVE_UUID_OSSP */
|
#else /* !HAVE_UUID_OSSP */
|
||||||
|
|
Loading…
Reference in a new issue