UUID Generator

UUIDs (Universally Unique Identifiers) are primarily used in distributed applications to generate identifiers that do not conflict. A UUID is 128 bits long and is guaranteed to be unique across space and time. This UUID generator is based on RFC 4122. From the IETF specification:

"UUIDs were originally used in the Apollo Network Computing System and later in the Open Software Foundation's (OSF) Distributed Computing Environment (DCE), and then in Microsoft Windows platforms."

The UUID format

A time-based UUID consists of a 60-bit time value, which allows for up to 10 million unique identifiers per machine per second. The time value is taken from the system clock, and is monotonically incrementing. However, since it is possible to set the system clock backward, a sequence number is added. The sequence number is incremented each time the UUID generator is started.

In this implementation the sequence number is also used to allow concurrent processes to share the same node identifier and run the UUID generator in-process, without generating duplicate identifiers.

Note that due to the structure of the UUID and the use of sequence number, there is no guarantee that UUID values themselves are monotonically incrementing. The UUID value cannot itself be used to sort based on order of creation, but provides an efficient index for storing and retrieving records based on their UUID.

A 48-bit node identifier prevents duplicate identifiers between machines. This implementation uses the IEEE 802 node identifier, aka as MAC address, taken from one of the network interface cards. It relies on the fact that network cards have unique MAC address numbers, and relieves the need to use a central authority.

The MAC address is obtained using ipconfig (Windows) or ifconfig (Unix, Linux, etc). If necessary, you can designate a MAC address manually by editing the uuid.state file.

Example

require_gem 'uuid'

10.times do
  p UUID.new
end

Produces:

"b6192b01-3d3b-0128-b3f7-000e35216048"
"b6192b02-3d3b-0128-b3f7-000e35216048"
"b6192b03-3d3b-0128-b3f7-000e35216048"
"b6195210-3d3b-0128-b3f7-000e35216048"
"b6195211-3d3b-0128-b3f7-000e35216048"
"b6195212-3d3b-0128-b3f7-000e35216048"
"b61c5f40-3d3b-0128-b3f7-000e35216048"
"b6236420-3d3b-0128-b3f7-000e35216048"
"b6236421-3d3b-0128-b3f7-000e35216048"
"b6236422-3d3b-0128-b3f7-000e35216048"

Download and Installation

You can download the sources directly, or install the GEM package (recommended) with

gem install uuid

Once installed, create a uuid.state file by running

uuid-setup

The latest version of the UUID generator can be found in the Reliable Messaging project

http://rubyforge.org/projects/reliable-msg/

For more information

http://trac.labnotes.org/cgi-bin/trac.cgi/wiki/Ruby/UuidGenerator

The UUID state file

The UUID generator uses a state file (uuid.state) to hold the MAC address and sequence number.

Use uuid-setup to create a UUID state file in the installation directory. If installed as a Gem, the state file will be generated in the Gem's directory. However, the UUID generator will look for the uuid.state file in the local directory first, before trying the installation directory. In some cases, you may prefer to use a state file in the local directory, and use a different state file for each application. Make sure that all state files use different MAC addresses to prevent duplicate identifiers.

A UUID state file looks like:

---
  last_clock: "0x28227f76122d80"
  mac_addr: 08-0E-46-21-4B-35
  sequence: "0x1639"

See Also

Some of the key concerns when designing this solution are how to select primary keys that will avoid collision and how to keep relational data in tact when syncing data from one database to another. The method I follow for this is to use a UUID or GUID as the primary key for every table, just like Active Directory. When I initially looked at Rails for this project this was a major concern. ActiveRecord ties an auto-incrementing integer as the primary key for all tables/models and I was worried about my ability to override that. Well with a little searching, reading and a tiny amount of effort I was able to get Rails to do exactly what was needed.

License

This package is licensed under the MIT license and/or the Creative Commons Attribution-ShareAlike.