summaryrefslogtreecommitdiff
path: root/sql/item_strfunc.cc
diff options
context:
space:
mode:
authorTatiana A. Nurnberg <azundris@mysql.com>2008-07-10 05:24:46 +0200
committerTatiana A. Nurnberg <azundris@mysql.com>2008-07-10 05:24:46 +0200
commit94607a836fdfa175e8056a121d5f0a6e63d532a3 (patch)
tree352779b09227d634606fc5130007f626c5e86c32 /sql/item_strfunc.cc
parent449d359fa00d29920518f1e9e1ffc0074f8c3aaf (diff)
parent2d41201c8a29edeecd51342bc5fbd4d953c3d5aa (diff)
downloadmariadb-git-94607a836fdfa175e8056a121d5f0a6e63d532a3.tar.gz
Bug#35848: UUID() returns UUIDs with the wrong time
offset for time part in UUIDs was 1/1000 of what it should be. In other words, offset was off. Also handle the case where we count into the future when several UUIDs are generated in one "tick", and then the next call is late enough for us to unwind some but not all of those borrowed ticks. Lastly, handle the case where we keep borrowing and borrowing until the tick-counter overflows by also changing into a new "numberspace" by creating a new random suffix.
Diffstat (limited to 'sql/item_strfunc.cc')
-rw-r--r--sql/item_strfunc.cc65
1 files changed, 53 insertions, 12 deletions
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 56aa44b453e..fbfd21aa006 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -3370,7 +3370,8 @@ static char clock_seq_and_node_str[]="-0000-000000000000";
number of 100-nanosecond intervals between
1582-10-15 00:00:00.00 and 1970-01-01 00:00:00.00.
*/
-#define UUID_TIME_OFFSET ((ulonglong) 141427 * 24 * 60 * 60 * 1000 * 10 )
+#define UUID_TIME_OFFSET ((ulonglong) 141427 * 24 * 60 * 60 * \
+ 1000 * 1000 * 10)
#define UUID_VERSION 0x1000
#define UUID_VARIANT 0x8000
@@ -3429,24 +3430,64 @@ String *Item_func_uuid::val_str(String *str)
set_clock_seq_str();
}
- ulonglong tv=my_getsystime() + UUID_TIME_OFFSET + nanoseq;
- if (unlikely(tv < uuid_time))
- set_clock_seq_str();
- else if (unlikely(tv == uuid_time))
+ ulonglong tv= my_getsystime() + UUID_TIME_OFFSET + nanoseq;
+
+ if (likely(tv > uuid_time))
{
- /* special protection from low-res system clocks */
- nanoseq++;
- tv++;
+ /*
+ Current time is ahead of last timestamp, as it should be.
+ If we "borrowed time", give it back, just as long as we
+ stay ahead of the previous timestamp.
+ */
+ if (nanoseq)
+ {
+ DBUG_ASSERT((tv > uuid_time) && (nanoseq > 0));
+ /*
+ -1 so we won't make tv= uuid_time for nanoseq >= (tv - uuid_time)
+ */
+ long delta= min(nanoseq, tv - uuid_time -1);
+ tv-= delta;
+ nanoseq-= delta;
+ }
}
else
{
- if (nanoseq)
+ if (unlikely(tv == uuid_time))
{
- tv-=nanoseq;
- nanoseq=0;
+ /*
+ For low-res system clocks. If several requests for UUIDs
+ end up on the same tick, we add a nano-second to make them
+ different.
+ ( current_timestamp + nanoseq * calls_in_this_period )
+ may end up > next_timestamp; this is OK. Nonetheless, we'll
+ try to unwind nanoseq when we get a chance to.
+ If nanoseq overflows, we'll start over with a new numberspace
+ (so the if() below is needed so we can avoid the ++tv and thus
+ match the follow-up if() if nanoseq overflows!).
+ */
+ if (likely(++nanoseq))
+ ++tv;
+ }
+
+ if (unlikely(tv <= uuid_time))
+ {
+ /*
+ If the admin changes the system clock (or due to Daylight
+ Saving Time), the system clock may be turned *back* so we
+ go through a period once more for which we already gave out
+ UUIDs. To avoid duplicate UUIDs despite potentially identical
+ times, we make a new random component.
+ We also come here if the nanoseq "borrowing" overflows.
+ In either case, we throw away any nanoseq borrowing since it's
+ irrelevant in the new numberspace.
+ */
+ set_clock_seq_str();
+ tv= my_getsystime() + UUID_TIME_OFFSET;
+ nanoseq= 0;
+ DBUG_PRINT("uuid",("making new numberspace"));
}
- DBUG_ASSERT(tv > uuid_time);
}
+
uuid_time=tv;
pthread_mutex_unlock(&LOCK_uuid_generator);