Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c941aed

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 25dd07e commit c941aed

File tree

1 file changed

+45
-31
lines changed

1 file changed

+45
-31
lines changed

contrib/uuid-ossp/uuid-ossp.c

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,42 @@ pguuid_complain(uuid_rc_t rc)
141141
errmsg("OSSP uuid library failure: error code %d", rc)));
142142
}
143143

144+
/*
145+
* We create a uuid_t object just once per session and re-use it for all
146+
* operations in this module. OSSP UUID caches the system MAC address and
147+
* other state in this object. Reusing the object has a number of benefits:
148+
* saving the cycles needed to fetch the system MAC address over and over,
149+
* reducing the amount of entropy we draw from /dev/urandom, and providing a
150+
* positive guarantee that successive generated V1-style UUIDs don't collide.
151+
* (On a machine fast enough to generate multiple UUIDs per microsecond,
152+
* or whatever the system's wall-clock resolution is, we'd otherwise risk
153+
* collisions whenever random initialization of the uuid_t's clock sequence
154+
* value chanced to produce duplicates.)
155+
*
156+
* However: when we're doing V3 or V5 UUID creation, uuid_make needs two
157+
* uuid_t objects, one holding the namespace UUID and one for the result.
158+
* It's unspecified whether it's safe to use the same uuid_t for both cases,
159+
* so let's cache a second uuid_t for use as the namespace holder object.
160+
*/
161+
static uuid_t *
162+
get_cached_uuid_t(int which)
163+
{
164+
static uuid_t *cached_uuid[2] = {NULL, NULL};
165+
166+
if (cached_uuid[which] == NULL)
167+
{
168+
uuid_rc_t rc;
169+
170+
rc = uuid_create(&cached_uuid[which]);
171+
if (rc != UUID_RC_OK)
172+
{
173+
cached_uuid[which] = NULL;
174+
pguuid_complain(rc);
175+
}
176+
}
177+
return cached_uuid[which];
178+
}
179+
144180
static char *
145181
uuid_to_string(const uuid_t *uuid)
146182
{
@@ -171,20 +207,14 @@ string_to_uuid(const char *str, uuid_t *uuid)
171207
static Datum
172208
special_uuid_value(const char *name)
173209
{
174-
uuid_t *uuid;
210+
uuid_t *uuid = get_cached_uuid_t(0);
175211
char *str;
176212
uuid_rc_t rc;
177213

178-
rc = uuid_create(&uuid);
179-
if (rc != UUID_RC_OK)
180-
pguuid_complain(rc);
181214
rc = uuid_load(uuid, name);
182215
if (rc != UUID_RC_OK)
183216
pguuid_complain(rc);
184217
str = uuid_to_string(uuid);
185-
rc = uuid_destroy(uuid);
186-
if (rc != UUID_RC_OK)
187-
pguuid_complain(rc);
188218

189219
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
190220
}
@@ -193,20 +223,14 @@ special_uuid_value(const char *name)
193223
static Datum
194224
uuid_generate_internal(int mode, const uuid_t *ns, const char *name, int len)
195225
{
196-
uuid_t *uuid;
226+
uuid_t *uuid = get_cached_uuid_t(0);
197227
char *str;
198228
uuid_rc_t rc;
199229

200-
rc = uuid_create(&uuid);
201-
if (rc != UUID_RC_OK)
202-
pguuid_complain(rc);
203230
rc = uuid_make(uuid, mode, ns, name);
204231
if (rc != UUID_RC_OK)
205232
pguuid_complain(rc);
206233
str = uuid_to_string(uuid);
207-
rc = uuid_destroy(uuid);
208-
if (rc != UUID_RC_OK)
209-
pguuid_complain(rc);
210234

211235
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
212236
}
@@ -215,26 +239,16 @@ uuid_generate_internal(int mode, const uuid_t *ns, const char *name, int len)
215239
static Datum
216240
uuid_generate_v35_internal(int mode, pg_uuid_t *ns, text *name)
217241
{
218-
uuid_t *ns_uuid;
219-
Datum result;
220-
uuid_rc_t rc;
242+
uuid_t *ns_uuid = get_cached_uuid_t(1);
221243

222-
rc = uuid_create(&ns_uuid);
223-
if (rc != UUID_RC_OK)
224-
pguuid_complain(rc);
225-
string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out, UUIDPGetDatum(ns))),
244+
string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out,
245+
UUIDPGetDatum(ns))),
226246
ns_uuid);
227247

228-
result = uuid_generate_internal(mode,
229-
ns_uuid,
230-
text_to_cstring(name),
231-
0);
232-
233-
rc = uuid_destroy(ns_uuid);
234-
if (rc != UUID_RC_OK)
235-
pguuid_complain(rc);
236-
237-
return result;
248+
return uuid_generate_internal(mode,
249+
ns_uuid,
250+
text_to_cstring(name),
251+
0);
238252
}
239253

240254
#else /* !HAVE_UUID_OSSP */

0 commit comments

Comments
 (0)