8000 When using the OSSP UUID library, cache its uuid_t state object. · larkly/postgres-docker@fd78544 · GitHub
[go: up one dir, main page]

Skip to content

Commit fd78544

Browse files
committed
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.
1 parent 1b20c63 commit fd78544

File tree

1 file changed

+44
-30
lines changed

1 file changed

+44
-30
lines changed

contrib/uuid-ossp/uuid-ossp.c

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,42 @@ pguuid_complain(uuid_rc_t rc)
7979
errmsg("OSSP uuid library failure: error code %d", rc)));
8080
}
8181

82+
/*
83+
* We create a uuid_t object just once per session and re-use it for all
84+
* operations in this module. OSSP UUID caches the system MAC address and
85+
* other state in this object. Reusing the object has a number of benefits:
86+
* saving the cycles needed to fetch the system MAC address over and over,
87+
* reducing the amount of entropy we draw from /dev/urandom, and providing a
88+
* positive guarantee that successive generated V1-style UUIDs don't collide.
89+
* (On a machine fast enough to generate multiple UUIDs per microsecond,
90+
* or whatever the system's wall-clock resolution is, we'd otherwise risk
91+
* collisions whenever random initialization of the uuid_t's clock sequence
92+
* value chanced to produce duplicates.)
93+
*
94+
* However: when we're doing V3 or V5 UUID creation, uuid_make needs two
95+
* uuid_t objects, one holding the namespace UUID and one for the result.
96+
* It's unspecified whether it's safe to use the same uuid_t for both cases,
97+
* so let's cache a second uuid_t for use as the namespace holder object.
98+
*/
99+
static uuid_t *
100+
get_cached_uuid_t(int which)
101+
{
102+
static uuid_t *cached_uuid[2] = {NULL, NULL};
103+
104+
if (cached_uuid[which] == NULL)
105+
{
106+
uuid_rc_t rc;
107+
108+
rc = uuid_create(&cached_uuid[which]);
109+
if (rc != UUID_RC_OK)
110+
{
111+
cached_uuid[which] = NULL;
112+
pguuid_complain(rc);
113+
}
114+
}
115+
return cached_uuid[which];
116+
}
117+
82118
static char *
83119
uuid_to_string(const uuid_t *uuid)
84120
{
@@ -109,20 +145,14 @@ string_to_uuid(const char *str, uuid_t *uuid)
109145
static Datum
110146
special_uuid_value(const char *name)
111147
{
112-
uuid_t *uuid;
148+
uuid_t *uuid = get_cached_uuid_t(0);
113149
char *str;
114150
uuid_rc_t rc;
115151

116-
rc = uuid_create(&uuid);
117-
if (rc != UUID_RC_OK)
118-
pguuid_complain(rc);
119152
rc = uuid_load(uuid, name);
120153
if (rc != UUID_RC_OK)
121154
pguuid_complain(rc);
122155
str = uuid_to_string(uuid);
123-
rc = uuid_destroy(uuid);
124-
if (rc != UUID_RC_OK)
125-
pguuid_complain(rc);
126156

127157
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
128158
}
@@ -166,20 +196,14 @@ uuid_ns_x500(PG_FUNCTION_ARGS)
166196
static Datum
167197
uuid_generate_internal(int mode, const uuid_t *ns, const char *name)
168198
{
169-
uuid_t *uuid;
199+
uuid_t *uuid = get_cached_uuid_t(0);
170200
char *str;
171201
uuid_rc_t rc;
172202

173-
rc = uuid_create(&uuid);
174-
if (rc != UUID_RC_OK)
175-
pguuid_complain(rc);
176203
rc = uuid_make(uuid, mode, ns, name);
177204
if (rc != UUID_RC_OK)
178205
pguuid_complain(rc);
179206
str = uuid_to_string(uuid);
180-
rc = uuid_destroy(uuid);
181-
if (rc != UUID_RC_OK)
182-
pguuid_complain(rc);
183207

184208
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
185209
}
@@ -202,25 +226,15 @@ uuid_generate_v1mc(PG_FUNCTION_ARGS)
202226
static Datum
203227
uuid_generate_v35_internal(int mode, pg_uuid_t *ns, text *name)
204228
{
205-
uuid_t *ns_uuid;
206-
Datum result;
207-
uuid_rc_t rc;
229+
uuid_t *ns_uuid = get_cached_uuid_t(1);
208230

209-
rc = uuid_create(&ns_uuid);
210-
if (rc != UUID_RC_OK)
211-
pguuid_complain(rc);
212-
string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out, UUIDPGetDatum(ns))),
231+
string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out,
232+
UUIDPGetDatum(ns))),
213233
ns_uuid);
214234

215-
result = uuid_generate_internal(mode,
216-
ns_uuid,
217-
text_to_cstring(name));
218-
219-
rc = uuid_destroy(ns_uuid);
220-
if (rc != UUID_RC_OK)
221-
pguuid_complain(rc);
222-
223-
return result;
235+
return uuid_generate_internal(mode,
236+
ns_uuid,
237+
text_to_cstring(name));
224238
}
225239

226240

0 commit comments

Comments
 (0)
0