[ace-users] [ace-bugs] UUID_Generator
Wim van den Boogaard
wim.van.den.boogaard at varianinc.com
Thu Sep 13 14:40:14 CDT 2007
Hello Doug,
I ran into an other problem when a lot UUIDs are generated quickly after
each other, again duplicates are generated. This is being caused by the
two occurences of the following line in UUID.cpp:
uuid_state_.clockSequence = static_cast<u_char>
((uuid_state_.clockSequence + 1) & ACE_UUID_CLOCK_SEQ_MASK);
This line should be:
uuid_state_.clockSequence = static_cast<ACE_UINT16>
((uuid_state_.clockSequence + 1) & ACE_UUID_CLOCK_SEQ_MASK);
Due to the casting to u_char instead of ACE_UINT16, duplicates are
generated after more then 255.
Kind regards,
Wim van den Boogaard.
> Hi Wim,
>
> ok, great, thanks for all the improvements and documentation. I'll
> check this in after the x.6 release goes out tomorrow.
>
> BTW, Johnny, I've made a pass through UUID.{h,inl,cpp} and
> "ACE-ified" everything. This may require some changes to user code,
> but the original API was totally inconsistent with ACE.
>
> Thanks,
>
> Doug
>
>
>> Thanks for the changes.
>>
>> This fix is working correctly for me.
>>
>> Changelog entry:
>> Implemented an accessor to obtain the timestamp and clockSequence in an
>> atomic manner. The clockSequence could change between the moment the
>> timestamp is obtained and the moment the clockSequence is used in a
>> multithreaded environment and that results in duplicate UUIDs.
>>
>> Kind regards,
>>
>> Wim van den Boogaard.
>>
>>> Hi Wim,
>>>
>>>
>>>
>>>> Hereby I sent you the source files, see attachments.
>>>>
>>>>
>>> Great, thanks!
>>>
>>>
>>>
>>>> Maybe it is better to rename the method get_timestamp to
>>>> get_timestampAndClocksequence.
>>>>
>>>>
>>> I've tweaked things a bit to ensure backwards compatibility with
>>> existing applications. Can you please check out
>>>
>>> http://www.dre.vanderbilt.edu/~schmidt/DOC_ROOT/ACE/ace/UUID.h
>>> http://www.dre.vanderbilt.edu/~schmidt/DOC_ROOT/ACE/ace/UUID.cpp
>>>
>>> and let me know if it's ok? Also, could you please send me a brief
>>> ChangeLog entry explaining what you've done and why.
>>>
>>> Thanks very much,
>>>
>>> Doug
>>>
>>>
>>>
>>>> Kind regards,
>>>>
>>>> Wim van den Boogaard
>>>>
>>>>
>>>>> Hi Wim,
>>>>>
>>>>> Thanks for using the PRF.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> ACE VERSION: 5.5.8 / 10
>>>>>>
>>>>>> HOST MACHINE and OPERATING SYSTEM:
>>>>>> WinXP
>>>>>>
>>>>>> TARGET MACHINE and OPERATING SYSTEM, if different from HOST:
>>>>>> COMPILER NAME AND VERSION (AND PATCHLEVEL):
>>>>>>
>>>>>> THE $ACE_ROOT/ace/config.h FILE [if you use a link to a platform-
>>>>>> specific file, simply state which one]:
>>>>>> config-win32.h
>>>>>>
>>>>>>
>>>>>> THE $ACE_ROOT/include/makeinclude/platform_macros.GNU FILE [if you
>>>>>> use a link to a platform-specific file, simply state which one
>>>>>> (unless this isn't used in this case, e.g., with Microsoft Visual
>>>>>> C++)]:
>>>>>>
>>>>>> CONTENTS OF $ACE_ROOT/bin/MakeProjectCreator/config/default.features
>>>>>> (used by MPC when you generate your own makefiles):
>>>>>> ---
>>>>>>
>>>>>> AREA/CLASS/EXAMPLE AFFECTED:
>>>>>>
>>>>>> DOES THE PROBLEM AFFECT:
>>>>>> COMPILATION?
>>>>>> LINKING
>>>>>> EXECUTION
>>>>>> OTHER (please specify)?
>>>>>>
>>>>>> SYNOPSIS:
>>>>>> Double UUID generated in a multi threaded application.
>>>>>>
>>>>>> DESCRIPTION:
>>>>>> The method UUID_Generator::generateUUID is not thread safe
>>>>>> in respect to the combination uuid_state_.clockSequence
>>>>>> and timestamp.
>>>>>> The combination timestamp and clockSequence should be
>>>>>> accessed in a thread safe manner. The method
>>>>>> UUID_Generator::get_timestamp returns the timestamp thread
>>>>>> safe, but also modifies the uuid_state_.clockSequence.
>>>>>> The uuid_state_.clockSequence is accessed thread safe in
>>>>>> UUID_Generator::generateUUID, but could have been modified
>>>>>> between the moment get_timestamp is being done and the
>>>>>> moment it is being used.
>>>>>>
>>>>>> REPEAT BY:
>>>>>>
>>>>>> SAMPLE FIX/WORKAROUND:
>>>>>> Return the timestamp and clockSequence in a atomic manner
>>>>>> via the get_timestamp method. I added an other argument
>>>>>> to the get_timestamp.
>>>>>> void get_timestamp(UUID_time& timestamp, ACE_UINT16& clockSequence);
>>>>>>
>>>>>> Return the actual clockSequence in the get_timestamp method.
>>>>>>
>>>>>>
>>>>>>
>>>>> Could you please send the code that implements this and we'll add it to ACE!
>>>>>
>>>>> Thanks,
>>>>>
>>>>> Doug
>>>>>
>>>>>
>>>>>
>>>>>
>>>> //$Id: UUID.cpp 78180 2007-04-25 07:05:02Z johnnyw $
>>>>
>>>> #include "ace/UUID.h"
>>>> #include "ace/Guard_T.h"
>>>>
>>>> #if !defined (__ACE_INLINE__)
>>>> #include "ace/UUID.inl"
>>>> #endif /* __ACE_INLINE__ */
>>>>
>>>> #include "ace/Log_Msg.h"
>>>> #include "ace/OS_NS_stdio.h"
>>>> #include "ace/OS_NS_string.h"
>>>> #include "ace/OS_NS_sys_time.h"
>>>> #include "ace/OS_NS_netdb.h"
>>>> #include "ace/OS_NS_unistd.h"
>>>> #include "ace/ACE.h"
>>>>
>>>> ACE_RCSID (ace,
>>>> UUID,
>>>> "$Id: UUID.cpp 78180 2007-04-25 07:05:02Z johnnyw $")
>>>>
>>>>
>>>> ACE_BEGIN_VERSIONED_NAMESPACE_DECL
>>>>
>>>> namespace ACE_Utils
>>>> {
>>>>
>>>> UUID_node::UUID_node (void)
>>>> {
>>>> for (int i = 0; i < UUID_node::NODE_ID_SIZE; ++i)
>>>> {
>>>> nodeID_[i] = 0;
>>>> }
>>>> }
>>>>
>>>> UUID_node::NodeID&
>>>> UUID_node::nodeID (void)
>>>> {
>>>> return nodeID_;
>>>> }
>>>>
>>>> void
>>>> UUID_node::nodeID (NodeID& nodeID)
>>>> {
>>>> for (int i = 0; i < UUID_node::NODE_ID_SIZE; ++i)
>>>> {
>>>> nodeID_[i] = nodeID[i];
>>>> }
>>>> }
>>>>
>>>> UUID UUID::NIL_UUID;
>>>>
>>>> /// Construct a nil UUID. Such a UUID has every one of it's data
>>>> /// elements set to zero.
>>>> UUID::UUID(void)
>>>> : timeLow_ (0),
>>>> timeMid_ (0),
>>>> timeHiAndVersion_ (0),
>>>> clockSeqHiAndReserved_ (0),
>>>> clockSeqLow_ (0),
>>>> node_ (0),
>>>> node_release_ (true),
>>>> as_string_ (0)
>>>> {
>>>> ACE_NEW (node_,
>>>> UUID_node);
>>>> }
>>>>
>>>> /// Construct a UUID from a string representation of an UUID.
>>>> UUID::UUID (const ACE_CString& uuid_string)
>>>> : timeLow_ (0),
>>>> timeMid_ (0),
>>>> timeHiAndVersion_ (0),
>>>> clockSeqHiAndReserved_ (0),
>>>> clockSeqLow_ (0),
>>>> node_ (0),
>>>> node_release_ (true),
>>>> as_string_ (0)
>>>> {
>>>> ACE_NEW (node_,
>>>> UUID_node);
>>>>
>>>> this->from_string_i (uuid_string);
>>>> }
>>>>
>>>> UUID::UUID(const UUID &right)
>>>> : timeLow_ (right.timeLow_),
>>>> timeMid_ (right.timeMid_),
>>>> timeHiAndVersion_ (right.timeHiAndVersion_),
>>>> clockSeqHiAndReserved_ (right.clockSeqHiAndReserved_),
>>>> clockSeqLow_ (right.clockSeqLow_),
>>>> as_string_ (0)
>>>> {
>>>> ACE_NEW (node_,
>>>> UUID_node (*right.node_));
>>>> }
>>>>
>>>> UUID::~UUID (void)
>>>> {
>>>> if (node_release_)
>>>> delete node_;
>>>>
>>>> if (as_string_ != 0)
>>>> delete as_string_;
>>>> }
>>>>
>>>> const ACE_CString*
>>>> UUID::to_string (void)
>>>> {
>>>> /// Only compute the string representation once.
>>>> if (as_string_ == 0)
>>>> {
>>>> // Get a buffer exactly the correct size. Use the nil UUID as a
>>>> // gauge. Don't forget the trailing nul.
>>>> size_t UUID_STRING_LENGTH = 36 + thr_id_.length () + pid_.length ();
>>>> char *buf = 0;
>>>>
>>>> if ((thr_id_.length () != 0) && (pid_.length () != 0))
>>>> {
>>>> UUID_STRING_LENGTH += 2; //for '-'
>>>> ACE_NEW_RETURN (buf,
>>>> char[UUID_STRING_LENGTH + 1],
>>>> 0);
>>>>
>>>> ACE_OS::sprintf(buf,
>>>> "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x-%s-%s",
>>>> this->timeLow_,
>>>> this->timeMid_,
>>>> this->timeHiAndVersion_,
>>>> this->clockSeqHiAndReserved_,
>>>> this->clockSeqLow_,
>>>> (this->node_->nodeID ()) [0],
>>>> (this->node_->nodeID ()) [1],
>>>> (this->node_->nodeID ()) [2],
>>>> (this->node_->nodeID ()) [3],
>>>> (this->node_->nodeID ()) [4],
>>>> (this->node_->nodeID ()) [5],
>>>> thr_id_.c_str (),
>>>> pid_.c_str ()
>>>> );
>>>> }
>>>> else
>>>> {
>>>> ACE_NEW_RETURN (buf,
>>>> char[UUID_STRING_LENGTH + 1],
>>>> 0);
>>>>
>>>> ACE_OS::sprintf (buf,
>>>> "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
>>>> this->timeLow_,
>>>> this->timeMid_,
>>>> this->timeHiAndVersion_,
>>>> this->clockSeqHiAndReserved_,
>>>> this->clockSeqLow_,
>>>> (this->node_->nodeID ()) [0],
>>>> (this->node_->nodeID ()) [1],
>>>> (this->node_->nodeID ()) [2],
>>>> (this->node_->nodeID ()) [3],
>>>> (this->node_->nodeID ()) [4],
>>>> (this->node_->nodeID ()) [5]
>>>> );
>>>> }
>>>>
>>>> // We allocated 'buf' above dynamically, so we shouldn't use
>>>> // ACE_NEW_RETURN here to avoid a possible memory leak.
>>>> ACE_NEW_NORETURN (this->as_string_,
>>>> ACE_CString (buf, UUID_STRING_LENGTH));
>>>>
>>>> // we first free the dynamically allocated 'buf'.
>>>> delete [] buf;
>>>>
>>>> // then we test that ACE_NEW succeded for 'as_string_'
>>>> // if not, we return 0 (NULL) to indicate failure.
>>>> if( this->as_string_ == 0 )
>>>> {
>>>> return 0;
>>>> }
>>>> }
>>>>
>>>> return as_string_;
>>>> }
>>>>
>>>> void
>>>> UUID::from_string_i (const ACE_CString& uuid_string)
>>>> {
>>>> if (uuid_string.length() < NIL_UUID.to_string ()->length ())
>>>> {
>>>> ACE_ERROR ((LM_ERROR,
>>>> "%N ACE_UUID::from_string_i - "
>>>> "IllegalArgument(incorrect string length)\n"));
>>>> return;
>>>> }
>>>>
>>>> /// Special case for the nil UUID.
>>>> if (uuid_string == *NIL_UUID.to_string ())
>>>> {
>>>> bool copy_constructor_not_supported = false;
>>>> ACE_ASSERT (copy_constructor_not_supported);
>>>> //*this = NIL_UUID;
>>>> ACE_UNUSED_ARG (copy_constructor_not_supported);
>>>> return;
>>>> }
>>>>
>>>> unsigned int timeLow;
>>>> unsigned int timeMid;
>>>> unsigned int timeHiAndVersion;
>>>> unsigned int clockSeqHiAndReserved;
>>>> unsigned int clockSeqLow;
>>>> unsigned int node [UUID_node::NODE_ID_SIZE];
>>>> char thr_pid_buf [BUFSIZ];
>>>>
>>>> if (uuid_string.length() == NIL_UUID.to_string()->length())
>>>> {
>>>> // This might seem quite strange this being in ACE, but it
>>>> // seems to be a bit difficult to write a facade for ::sscanf
>>>> // because some compilers dont support vsscanf, including
>>>> // MSVC. It appears that most platforms support sscanf though
>>>> // so we need to use it directly.
>>>> const int nScanned =
>>>> #if defined (ACE_HAS_TR24731_2005_CRT)
>>>> sscanf_s (
>>>> #else
>>>> ::sscanf(
>>>> #endif
>>>> uuid_string.c_str(),
>>>> "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x",
>>>> &timeLow,
>>>> &timeMid,
>>>> &timeHiAndVersion,
>>>> &clockSeqHiAndReserved,
>>>> &clockSeqLow,
>>>> &node[0],
>>>> &node[1],
>>>> &node[2],
>>>> &node[3],
>>>> &node[4],
>>>> &node[5]
>>>> );
>>>>
>>>> if (nScanned != 11)
>>>> {
>>>> ACE_DEBUG ((LM_DEBUG,
>>>> "UUID::from_string_i - "
>>>> "IllegalArgument(invalid string representation)\n"));
>>>> return;
>>>> }
>>>> }
>>>> else
>>>> {
>>>> const int nScanned =
>>>> #if defined (ACE_HAS_TR24731_2005_CRT)
>>>> sscanf_s (uuid_string.c_str(),
>>>> "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x-%s",
>>>> &timeLow,
>>>> &timeMid,
>>>> &timeHiAndVersion,
>>>> &clockSeqHiAndReserved,
>>>> &clockSeqLow,
>>>> &node[0],
>>>> &node[1],
>>>> &node[2],
>>>> &node[3],
>>>> &node[4],
>>>> &node[5],
>>>> thr_pid_buf,
>>>> BUFSIZ
>>>> );
>>>> #else
>>>> ::sscanf (uuid_string.c_str(),
>>>> "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x-%s",
>>>> &timeLow,
>>>> &timeMid,
>>>> &timeHiAndVersion,
>>>> &clockSeqHiAndReserved,
>>>> &clockSeqLow,
>>>> &node[0],
>>>> &node[1],
>>>> &node[2],
>>>> &node[3],
>>>> &node[4],
>>>> &node[5],
>>>> thr_pid_buf
>>>> );
>>>> #endif /* ACE_HAS_TR24731_2005_CRT */
>>>>
>>>> if (nScanned != 12)
>>>> {
>>>> ACE_DEBUG ((LM_DEBUG,
>>>> "ACE_UUID::from_string_i - "
>>>> "IllegalArgument(invalid string representation)\n"));
>>>> return;
>>>> }
>>>> }
>>>>
>>>> this->timeLow_ = static_cast<ACE_UINT32> (timeLow);
>>>> this->timeMid_ = static_cast<ACE_UINT16> (timeMid);
>>>> this->timeHiAndVersion_ = static_cast<ACE_UINT16> (timeHiAndVersion);
>>>> this->clockSeqHiAndReserved_ = static_cast<u_char> (clockSeqHiAndReserved);
>>>> this->clockSeqLow_ = static_cast<u_char> (clockSeqLow);
>>>>
>>>> UUID_node::NodeID nodeID;
>>>> for (int i = 0; i < UUID_node::NODE_ID_SIZE; ++i)
>>>> nodeID [i] = static_cast<u_char> (node[i]);
>>>>
>>>> this->node_->nodeID (nodeID);
>>>>
>>>> // Support varient 10- only
>>>> if ((this->clockSeqHiAndReserved_ & 0xc0) != 0x80 && (this->clockSeqHiAndReserved_ & 0xc0) != 0xc0)
>>>> {
>>>> ACE_DEBUG ((LM_DEBUG,
>>>> "ACE_UUID::from_string_i - "
>>>> "IllegalArgument(unsupported variant)\n"));
>>>> return;
>>>> }
>>>>
>>>> /// Support versions 1, 3, and 4 only
>>>> ACE_UINT16 V1 = this->timeHiAndVersion_;
>>>>
>>>> if ((V1 & 0xF000) != 0x1000 &&
>>>> (V1 & 0xF000) != 0x3000 &&
>>>> (V1 & 0xF000) != 0x4000)
>>>> {
>>>> ACE_DEBUG ((LM_DEBUG,
>>>> "ACE_UUID::from_string_i - "
>>>> "IllegalArgument(unsupported version)\n"));
>>>> return;
>>>> }
>>>> if ((this->clockSeqHiAndReserved_ & 0xc0) == 0xc0)
>>>> {
>>>> if (uuid_string.length() == NIL_UUID.to_string()->length())
>>>> {
>>>> ACE_DEBUG ((LM_DEBUG,
>>>> "ACE_UUID::from_string_i - "
>>>> "IllegalArgument (Missing Thread and Process Id)\n"));
>>>> return;
>>>> }
>>>> ACE_CString thr_pid_str (thr_pid_buf);
>>>> ssize_t pos = static_cast<ssize_t> (thr_pid_str.find ('-'));
>>>> if (pos == -1)
>>>> ACE_DEBUG ((LM_DEBUG,
>>>> "ACE_UUID::from_string_i - "
>>>> "IllegalArgument (Thread and Process Id format incorrect)\n"));
>>>>
>>>> this->thr_id_ = thr_pid_str.substr (0, pos);
>>>> this->pid_ = thr_pid_str.substr (pos+1, thr_pid_str.length ()-pos-1);
>>>> }
>>>> }
>>>>
>>>> UUID_Generator::UUID_Generator ()
>>>> : timeLast_ (0),
>>>> destroy_lock_ (true)
>>>> {
>>>> ACE_NEW (lock_,
>>>> ACE_SYNCH_MUTEX);
>>>> }
>>>>
>>>> UUID_Generator::~UUID_Generator()
>>>> {
>>>> if (destroy_lock_)
>>>> delete lock_;
>>>> }
>>>>
>>>> void
>>>> UUID_Generator::init (void)
>>>> {
>>>> ACE_OS::macaddr_node_t macaddress;
>>>> int result = ACE_OS::getmacaddress (&macaddress);
>>>>
>>>> UUID_node::NodeID nodeID;
>>>> if (result != -1)
>>>> {
>>>> // ACE_DEBUG ((LM_DEBUG,
>>>> // "%02X-%02X-%02X-%02X-%02X-%02X\n",
>>>> // macaddress.node [0],
>>>> // macaddress.node [1],
>>>> // macaddress.node [2],
>>>> // macaddress.node [3],
>>>> // macaddress.node [4],
>>>> // macaddress.node [5]));
>>>>
>>>> ACE_OS::memcpy (&nodeID,
>>>> macaddress.node,
>>>> sizeof (nodeID));
>>>> }
>>>> else
>>>> {
>>>> nodeID [0] = static_cast<u_char> (ACE_OS::rand());
>>>> nodeID [1] = static_cast<u_char> (ACE_OS::rand());
>>>> nodeID [2] = static_cast<u_char> (ACE_OS::rand());
>>>> nodeID [3] = static_cast<u_char> (ACE_OS::rand());
>>>> nodeID [4] = static_cast<u_char> (ACE_OS::rand());
>>>> nodeID [5] = static_cast<u_char> (ACE_OS::rand());
>>>> }
>>>>
>>>> ACE_UINT16 dummy;
>>>> this->get_timestamp (timeLast_,dummy);
>>>>
>>>> {
>>>> ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, *lock_);
>>>> uuid_state_.timestamp = timeLast_;
>>>> uuid_state_.node.nodeID (nodeID);
>>>> }
>>>> }
>>>>
>>>>
>>>> void
>>>> UUID_Generator::generateUUID (UUID& uuid,ACE_UINT16 version, u_char variant)
>>>> {
>>>> UUID_time timestamp;
>>>> ACE_UINT16 clockSequence;
>>>> this->get_timestamp (timestamp,clockSequence);
>>>>
>>>>
>>>> // Construct a Version 1 UUID with the information in the arguements.
>>>> uuid.timeLow (static_cast<ACE_UINT32> (timestamp & 0xFFFFFFFF));
>>>> uuid.timeMid (static_cast<ACE_UINT16> ((timestamp >> 32) & 0xFFFF));
>>>>
>>>>
>>>> ACE_UINT16 tHAV = static_cast<ACE_UINT16> ((timestamp >> 48) & 0xFFFF);
>>>> tHAV |= (version << 12);
>>>> uuid.timeHiAndVersion (tHAV);
>>>>
>>>> u_char cseqHAV;
>>>> uuid.clockSeqLow (static_cast<u_char> (clockSequence & 0xFF));
>>>> cseqHAV = static_cast<u_char> ((clockSequence & 0x3f00) >> 8);
>>>> uuid_state_.timestamp = timestamp;
>>>>
>>>> cseqHAV |= variant;
>>>> uuid.clockSeqHiAndReserved (cseqHAV);
>>>> uuid.node (&(uuid_state_.node));
>>>>
>>>> if (variant == 0xc0)
>>>> {
>>>> ACE_Thread_ID thread_id;
>>>> char buf [BUFSIZ];
>>>> thread_id.to_string (buf);
>>>> uuid.thr_id (buf);
>>>>
>>>> ACE_OS::sprintf (buf,
>>>> "%d",
>>>> static_cast<int> (ACE_OS::getpid ()));
>>>> uuid.pid (buf);
>>>> }
>>>> }
>>>>
>>>> UUID*
>>>> UUID_Generator::generateUUID (ACE_UINT16 version, u_char variant)
>>>> {
>>>> UUID* uuid;
>>>> ACE_NEW_RETURN (uuid,
>>>> UUID,
>>>> 0);
>>>>
>>>> this->generateUUID (*uuid, version, variant);
>>>> return uuid;
>>>> }
>>>>
>>>> /// Obtain a new timestamp. If UUID's are being generated too quickly
>>>> /// the clock sequence will be incremented
>>>> void
>>>> UUID_Generator::get_timestamp (UUID_time& timestamp,ACE_UINT16& clockSequence)
>>>> {
>>>> ACE_GUARD (ACE_SYNCH_MUTEX, mon, *lock_);
>>>>
>>>> this->get_systemtime(timestamp);
>>>>
>>>> // Account for the clock being set back. Increment the clock /
>>>> // sequence.
>>>> if (timestamp <= timeLast_)
>>>> uuid_state_.clockSequence = static_cast<u_char> ((uuid_state_.clockSequence + 1) & ACE_UUID_CLOCK_SEQ_MASK);
>>>>
>>>> // If the system time ticked since the last UUID was
>>>> // generated. Set / the clock sequence back.
>>>> else if (timestamp > timeLast_)
>>>> uuid_state_.clockSequence = 0;
>>>>
>>>> timeLast_ = timestamp;
>>>> clockSequence = uuid_state_.clockSequence;
>>>> }
>>>>
>>>> /**
>>>> * ACE_Time_Value is in POSIX time, seconds since Jan 1, 1970. UUIDs use
>>>> * time in 100ns ticks since 15 October 1582. The difference is:
>>>> * 15 Oct 1582 - 1 Jan 1600: 17 days in Oct, 30 in Nov, 31 in Dec +
>>>> * 17 years and 4 leap days (1584, 88, 92 and 96)
>>>> * 1 Jan 1600 - 1 Jan 1900: 3 centuries + 73 leap days ( 25 in 17th cent.
>>>> * and 24 each in 18th and 19th centuries)
>>>> * 1 Jan 1900 - 1 Jan 1970: 70 years + 17 leap days.
>>>> * This adds up, in days: (17+30+31+365*17+4)+(365*300+73)+(365*70+17) or
>>>> * 122192928000000000U (0x1B21DD213814000) 100 ns ticks.
>>>> */
>>>> void
>>>> UUID_Generator::get_systemtime (UUID_time & timestamp)
>>>> {
>>>> const UUID_time timeOffset =
>>>> #if defined (ACE_LACKS_UNSIGNEDLONGLONG_T)
>>>> ACE_U_LongLong (ACE_INT64_LITERAL (0x1B21DD213814000));
>>>> #elif defined (ACE_LACKS_LONGLONG_T)
>>>> ACE_U_LongLong (0x13814000u, 0x1B21DD2u);
>>>> #else
>>>> ACE_UINT64_LITERAL (0x1B21DD213814000);
>>>> #endif /* ACE_LACKS_UNSIGNEDLONGLONG_T */
>>>>
>>>> /// Get the time of day, convert to 100ns ticks then add the offset.
>>>> ACE_Time_Value now = ACE_OS::gettimeofday();
>>>> ACE_UINT64 time;
>>>> now.to_usec (time);
>>>> time = time * 10;
>>>> timestamp = time + timeOffset;
>>>> }
>>>>
>>>> ACE_SYNCH_MUTEX*
>>>> UUID_Generator::lock (void)
>>>> {
>>>> return this->lock_;
>>>> }
>>>>
>>>> void
>>>> UUID_Generator::lock (ACE_SYNCH_MUTEX* lock,
>>>> bool release_lock)
>>>> {
>>>> if (this->destroy_lock_)
>>>> delete this->lock_;
>>>>
>>>> this->lock_ = lock;
>>>> this->destroy_lock_ = release_lock;
>>>> }
>>>>
>>>> }
>>>>
>>>> #if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION)
>>>> template ACE_Singleton<ACE_Utils::UUID_Generator, ACE_SYNCH_MUTEX> *
>>>> ACE_Singleton<ACE_Utils::UUID_Generator, ACE_SYNCH_MUTEX>::singleton_;
>>>> #endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */
>>>>
>>>> ACE_END_VERSIONED_NAMESPACE_DECL
>>>> // -*- C++ -*-
>>>>
>>>> //=============================================================================
>>>> /**
>>>> * @file UUID.h
>>>> *
>>>> * $Id: UUID.h 74958 2006-10-23 23:31:00Z ossama $
>>>> *
>>>> * @author Andrew T. Finnel <andrew at activesol.net>
>>>> * @author Yamuna Krishnmaurthy <yamuna at oomworks.com>
>>>> */
>>>> //=============================================================================
>>>>
>>>> #ifndef ACE_UUID_H
>>>> #define ACE_UUID_H
>>>> #include /**/ "ace/pre.h"
>>>>
>>>> #include /**/ "ace/config-all.h"
>>>>
>>>> #if !defined (ACE_LACKS_PRAGMA_ONCE)
>>>> # pragma once
>>>> #endif /* ACE_LACKS_PRAGMA_ONCE */
>>>>
>>>> #include "ace/SString.h"
>>>> #include "ace/Singleton.h"
>>>> #include "ace/Synch_Traits.h"
>>>>
>>>> ACE_BEGIN_VERSIONED_NAMESPACE_DECL
>>>>
>>>> namespace ACE_Utils
>>>> {
>>>> /// Class to hold a MAC address
>>>> class ACE_Export UUID_node
>>>> {
>>>> public:
>>>>
>>>> /// Constructor
>>>> UUID_node (void);
>>>>
>>>> enum {NODE_ID_SIZE = 6};
>>>> typedef u_char NodeID[NODE_ID_SIZE];
>>>>
>>>> NodeID& nodeID (void);
>>>> void nodeID (NodeID&);
>>>>
>>>> ///// Equality Operations
>>>> bool operator == (const UUID_node& right) const;
>>>> bool operator != (const UUID_node& right) const;
>>>>
>>>> ///// Relational Operations
>>>> //bool operator < (const UUID_node& right) const;
>>>>
>>>> private:
>>>> NodeID nodeID_;
>>>> };
>>>>
>>>>
>>>>
>>>> /**
>>>> * @class ACE_UUID
>>>> *
>>>> * ACE_UUID represents a Universally Unique IDentifier (UUID) as
>>>> * described in (the expired) INTERNET-DRAFT specification entitled
>>>> * UUIDs and GUIDs. All instances of UUID are of the time-based
>>>> * variety. That is, the version number part of the timeHiAndVersion
>>>> * field is 1.
>>>> *
>>>> * The default constructor creates a nil UUID.
>>>> *
>>>> * UUIDs have value semantics. In addition, they may be compared for
>>>> * ordering and equality.
>>>> *
>>>> * Additionally in this implementation provisions have been made to include
>>>> * process and thread ids to make the UUIDs more unique. The variant 0xc0
>>>> * has been added to facilitate this.
>>>> */
>>>> class ACE_Export UUID
>>>> {
>>>> public:
>>>>
>>>> /// Constructor
>>>> UUID (void);
>>>>
>>>> /// Constructs a UUID from a string representation.
>>>> UUID (const ACE_CString& uuidString);
>>>>
>>>> UUID (const UUID &right);
>>>>
>>>> // Destructor
>>>> ~UUID (void);
>>>>
>>>> ACE_UINT32 timeLow (void) const;
>>>> void timeLow (ACE_UINT32);
>>>>
>>>> ACE_UINT16 timeMid (void) const;
>>>> void timeMid (ACE_UINT16);
>>>>
>>>> ACE_UINT16 timeHiAndVersion (void) const;
>>>> void timeHiAndVersion (ACE_UINT16);
>>>>
>>>> u_char clockSeqHiAndReserved (void) const;
>>>> void clockSeqHiAndReserved (u_char);
>>>>
>>>> u_char clockSeqLow (void) const;
>>>> void clockSeqLow (u_char);
>>>>
>>>> UUID_node* node (void) const;
>>>> void node (UUID_node*);
>>>>
>>>> ACE_CString* thr_id (void);
>>>> void thr_id (char*);
>>>>
>>>> ACE_CString* pid (void);
>>>> void pid (char*);
>>>>
>>>> /// Returns a string representation of the UUID
>>>> const ACE_CString* to_string (void);
>>>>
>>>> /// Set the value using a string
>>>> void from_string (const ACE_CString& uuid_string);
>>>>
>>>> static UUID NIL_UUID;
>>>>
>>>> /// Equality Operations
>>>> bool operator== (const UUID &right) const;
>>>> bool operator!= (const UUID &right) const;
>>>>
>>>> /// Relational Operations
>>>> //bool operator< (const UUID &right) const;
>>>> //bool operator> (const UUID &right) const;
>>>> //bool operator<= (const UUID &right) const;
>>>> //bool operator>= (const UUID &right) const;
>>>>
>>>> private:
>>>> void from_string_i (const ACE_CString& uuidString);
>>>>
>>>> UUID& operator= (const UUID&);
>>>>
>>>> /// Data Members for Class Attributes
>>>> ACE_UINT32 timeLow_;
>>>> ACE_UINT16 timeMid_;
>>>> ACE_UINT16 timeHiAndVersion_;
>>>> u_char clockSeqHiAndReserved_;
>>>> u_char clockSeqLow_;
>>>> UUID_node* node_;
>>>> bool node_release_;
>>>> ACE_CString thr_id_;
>>>> ACE_CString pid_;
>>>>
>>>> /// The string representation of the UUID. This is created and
>>>> /// updated only on demand.
>>>> ACE_CString *as_string_;
>>>> };
>>>>
>>>>
>>>> /**
>>>> * @class ACE_UUID_Generator
>>>> *
>>>> * Singleton class that generates UUIDs.
>>>> *
>>>> */
>>>> class ACE_Export UUID_Generator
>>>> {
>>>> public:
>>>>
>>>> enum {ACE_UUID_CLOCK_SEQ_MASK = 0x3FFF};
>>>>
>>>> UUID_Generator();
>>>> ~UUID_Generator();
>>>>
>>>> void init (void);
>>>>
>>>> /// Format timestamp, clockseq, and nodeID into an UUID of the
>>>> /// specified version and variant. For generating UUID's with
>>>> /// thread and process ids use variant=0xc0
>>>> void generateUUID (UUID&, ACE_UINT16 version=0x0001, u_char variant=0x80);
>>>>
>>>> /// Format timestamp, clockseq, and nodeID into a VI UUID. For
>>>> /// generating UUID's with thread and process ids use variant=0xc0
>>>> UUID* generateUUID (ACE_UINT16 version=0x0001, u_char variant=0x80);
>>>>
>>>> /// Type to represent UTC as a count of 100 nanosecond intervals
>>>> /// since 00:00:00.00, 15 October 1582.
>>>> typedef ACE_UINT64 UUID_time;
>>>>
>>>> /// The locking strategy prevents multiple generators from accessing
>>>> /// the UUID_state at the same time. Get the locking strategy.
>>>> ACE_SYNCH_MUTEX* lock (void);
>>>>
>>>> /// Set a new locking strategy and return the old one.
>>>> void lock (ACE_SYNCH_MUTEX* lock,
>>>> bool release_lock);
>>>>
>>>> private:
>>>>
>>>> /// The system time when that last uuid was generated.
>>>> UUID_time timeLast_;
>>>>
>>>> /// Type to contain the UUID generator persistent state. This will
>>>> /// be kept in memory mapped shared memory
>>>> struct UUID_State
>>>> {
>>>> UUID_time timestamp;
>>>> UUID_node node;
>>>> ACE_UINT16 clockSequence;
>>>> };
>>>>
>>>> /// Obtain a UUID timestamp. Compensate for the fact that the time
>>>> /// obtained from getSystem time has a resolution less than 100ns.
>>>> void get_timestamp (UUID_time& timestamp, ACE_UINT16& clockSequence);
>>>>
>>>> /// Obtain the system time in UTC as a count of 100 nanosecond intervals
>>>> /// since 00:00:00.00, 15 October 1582 (the date of Gregorian reform to
>>>> /// the Christian calendar).
>>>> void get_systemtime( UUID_time& timeNow);
>>>>
>>>> /// The UUID generator persistent state.
>>>> UUID_State uuid_state_;
>>>>
>>>> ACE_SYNCH_MUTEX* lock_;
>>>> bool destroy_lock_;
>>>> };
>>>>
>>>> typedef ACE_Singleton<UUID_Generator, ACE_SYNCH_MUTEX> UUID_GENERATOR;
>>>>
>>>> }
>>>>
>>>> ACE_END_VERSIONED_NAMESPACE_DECL
>>>>
>>>> #if defined (__ACE_INLINE__)
>>>> #include "ace/UUID.inl"
>>>> #endif /* __ACE_INLINE__ */
>>>>
>>>> #include /**/ "ace/post.h"
>>>> #endif // ACE_UUID_H
>>>>
>>>>
>>>
>>>
>
>
>
More information about the Ace-users
mailing list