lexical_uuid 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lexical_uuid.gemspec +24 -29
- data/lib/increasing_microsecond_clock.rb +33 -0
- data/lib/lexical_uuid.rb +16 -55
- data/lib/time_ext.rb +10 -0
- data/spec/lexical_uuid_spec.rb +14 -41
- metadata +11 -11
data/Rakefile
CHANGED
@@ -11,7 +11,7 @@ begin
|
|
11
11
|
gem.homepage = "http://github.com/jamesgolick/lexical_uuid"
|
12
12
|
gem.authors = ["James Golick"]
|
13
13
|
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
-
gem.add_dependency "
|
14
|
+
gem.add_dependency "fnv"
|
15
15
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
16
|
end
|
17
17
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lexical_uuid.gemspec
CHANGED
@@ -1,58 +1,53 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
8
|
-
s.version = "0.
|
7
|
+
s.name = "lexical_uuid"
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["James Golick"]
|
12
|
-
s.date =
|
13
|
-
s.description =
|
14
|
-
s.email =
|
12
|
+
s.date = "2011-09-23"
|
13
|
+
s.description = "UUIDs that are byte-ordered lamport clocks (timestamp, worker_id). Much simpler than type-1 UUID's crappy, weirdo layout."
|
14
|
+
s.email = "jamesgolick@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
17
|
-
|
17
|
+
"README.rdoc"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
20
|
".document",
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
"spec/spec.opts",
|
30
|
-
"spec/spec_helper.rb"
|
31
|
-
]
|
32
|
-
s.homepage = %q{http://github.com/jamesgolick/lexical_uuid}
|
33
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
34
|
-
s.require_paths = ["lib"]
|
35
|
-
s.rubygems_version = %q{1.3.7}
|
36
|
-
s.summary = %q{UUIDs that are byte-ordered lamport clocks (timestamp, worker_id). Much simpler than type-1 UUID's crappy, weirdo layout.}
|
37
|
-
s.test_files = [
|
21
|
+
"LICENSE",
|
22
|
+
"README.rdoc",
|
23
|
+
"Rakefile",
|
24
|
+
"VERSION",
|
25
|
+
"lexical_uuid.gemspec",
|
26
|
+
"lib/increasing_microsecond_clock.rb",
|
27
|
+
"lib/lexical_uuid.rb",
|
28
|
+
"lib/time_ext.rb",
|
38
29
|
"spec/lexical_uuid_spec.rb",
|
39
|
-
|
30
|
+
"spec/spec.opts",
|
31
|
+
"spec/spec_helper.rb"
|
40
32
|
]
|
33
|
+
s.homepage = "http://github.com/jamesgolick/lexical_uuid"
|
34
|
+
s.require_paths = ["lib"]
|
35
|
+
s.rubygems_version = "1.8.10"
|
36
|
+
s.summary = "UUIDs that are byte-ordered lamport clocks (timestamp, worker_id). Much simpler than type-1 UUID's crappy, weirdo layout."
|
41
37
|
|
42
38
|
if s.respond_to? :specification_version then
|
43
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
44
39
|
s.specification_version = 3
|
45
40
|
|
46
41
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
47
42
|
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
48
|
-
s.add_runtime_dependency(%q<
|
43
|
+
s.add_runtime_dependency(%q<fnv>, [">= 0"])
|
49
44
|
else
|
50
45
|
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
51
|
-
s.add_dependency(%q<
|
46
|
+
s.add_dependency(%q<fnv>, [">= 0"])
|
52
47
|
end
|
53
48
|
else
|
54
49
|
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
55
|
-
s.add_dependency(%q<
|
50
|
+
s.add_dependency(%q<fnv>, [">= 0"])
|
56
51
|
end
|
57
52
|
end
|
58
53
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
class IncreasingMicrosecondClock
|
4
|
+
def initialize(timestamp_factory = lambda { Time.stamp },
|
5
|
+
mutex = Mutex.new)
|
6
|
+
@timestamp_factory = timestamp_factory
|
7
|
+
@mutex = mutex
|
8
|
+
@time = @timestamp_factory.call
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
@mutex.synchronize {
|
13
|
+
new_time = @timestamp_factory.call
|
14
|
+
|
15
|
+
@time =
|
16
|
+
if new_time > @time
|
17
|
+
new_time
|
18
|
+
else
|
19
|
+
@time + 1
|
20
|
+
end
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
@instance = new
|
25
|
+
|
26
|
+
class << self
|
27
|
+
attr_accessor :instance
|
28
|
+
|
29
|
+
def call
|
30
|
+
instance.call
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/lexical_uuid.rb
CHANGED
@@ -1,35 +1,8 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "socket"
|
3
|
-
require "
|
4
|
-
|
5
|
-
|
6
|
-
inline :C do |builder|
|
7
|
-
builder.c <<-__END__
|
8
|
-
static long fnv1a() {
|
9
|
-
int hash = 2166136261;
|
10
|
-
int i = 0;
|
11
|
-
|
12
|
-
for(i = 0; i < RSTRING_LEN(self); i++) {
|
13
|
-
hash ^= RSTRING_PTR(self)[i];
|
14
|
-
hash *= 16777619;
|
15
|
-
}
|
16
|
-
|
17
|
-
return hash;
|
18
|
-
}
|
19
|
-
__END__
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# Borrowed from the SimpleUUID gem
|
24
|
-
class Time
|
25
|
-
def self.stamp
|
26
|
-
Time.now.stamp
|
27
|
-
end
|
28
|
-
|
29
|
-
def stamp
|
30
|
-
to_i * 1_000_000 + usec
|
31
|
-
end
|
32
|
-
end
|
3
|
+
require "fnv"
|
4
|
+
require File.join(File.dirname(__FILE__), "time_ext")
|
5
|
+
require File.join(File.dirname(__FILE__), "increasing_microsecond_clock")
|
33
6
|
|
34
7
|
class LexicalUUID
|
35
8
|
class << self
|
@@ -41,17 +14,16 @@ class LexicalUUID
|
|
41
14
|
def create_worker_id
|
42
15
|
fqdn = Socket.gethostbyname(Socket.gethostname).first
|
43
16
|
pid = Process.pid
|
44
|
-
"#{fqdn}-#{pid}"
|
17
|
+
FNV.new.fnv1a_64("#{fqdn}-#{pid}")
|
45
18
|
end
|
46
19
|
end
|
47
20
|
|
48
|
-
attr_reader :worker_id, :
|
21
|
+
attr_reader :worker_id, :timestamp
|
49
22
|
|
50
|
-
def initialize(timestamp = nil,
|
23
|
+
def initialize(timestamp = nil, worker_id = nil, timestamp_factory = IncreasingMicrosecondClock)
|
51
24
|
case timestamp
|
52
25
|
when Fixnum, Bignum
|
53
26
|
@timestamp = timestamp
|
54
|
-
@jitter = jitter || create_jitter
|
55
27
|
@worker_id = worker_id || self.class.worker_id
|
56
28
|
when String
|
57
29
|
case timestamp.size
|
@@ -59,27 +31,25 @@ class LexicalUUID
|
|
59
31
|
from_bytes(timestamp)
|
60
32
|
when 36
|
61
33
|
elements = timestamp.split("-")
|
62
|
-
from_bytes(
|
34
|
+
from_bytes(elements.join.to_a.pack('H32'))
|
63
35
|
else
|
64
36
|
raise ArgumentError,
|
65
37
|
"#{timestamp} was incorrectly sized. Must be 16 timestamp."
|
66
38
|
end
|
67
39
|
when Time
|
68
40
|
@timestamp = timestamp.stamp
|
69
|
-
@jitter = create_jitter
|
70
41
|
@worker_id = self.class.worker_id
|
71
42
|
when nil
|
72
43
|
@worker_id = self.class.worker_id
|
73
|
-
@
|
74
|
-
@timestamp = Time.stamp
|
44
|
+
@timestamp = timestamp_factory.call
|
75
45
|
end
|
76
46
|
end
|
77
47
|
|
78
48
|
def to_bytes
|
79
49
|
[timestamp >> 32,
|
80
|
-
|
81
|
-
|
82
|
-
|
50
|
+
timestamp & 0xffffffff,
|
51
|
+
worker_id >> 32,
|
52
|
+
worker_id & 0xffffffff].pack("NNNN")
|
83
53
|
end
|
84
54
|
|
85
55
|
# Also borrowed from simple_uuid
|
@@ -91,20 +61,14 @@ class LexicalUUID
|
|
91
61
|
end
|
92
62
|
|
93
63
|
def <=>(other)
|
94
|
-
|
95
|
-
worker_id <=> other.worker_id
|
96
|
-
elsif timestamp == other.timestamp
|
97
|
-
jitter <=> other.jitter
|
98
|
-
else
|
99
|
-
timestamp <=> other.timestamp
|
100
|
-
end
|
64
|
+
timestamp == other.timestamp ?
|
65
|
+
worker_id <=> other.worker_id : timestamp <=> other.timestamp
|
101
66
|
end
|
102
67
|
|
103
68
|
def ==(other)
|
104
69
|
other.is_a?(LexicalUUID) &&
|
105
70
|
timestamp == other.timestamp &&
|
106
|
-
|
107
|
-
worker_id == other.worker_id
|
71
|
+
worker_id == other.worker_id
|
108
72
|
end
|
109
73
|
|
110
74
|
def eql?(other)
|
@@ -117,11 +81,8 @@ class LexicalUUID
|
|
117
81
|
|
118
82
|
private
|
119
83
|
def from_bytes(bytes)
|
120
|
-
time_high, time_low,
|
84
|
+
time_high, time_low, worker_high, worker_low = bytes.unpack("NNNN")
|
121
85
|
@timestamp = (time_high << 32) | time_low
|
122
|
-
|
123
|
-
|
124
|
-
def create_jitter
|
125
|
-
rand(2**32)
|
86
|
+
@worker_id = (worker_high << 32) | worker_low
|
126
87
|
end
|
127
88
|
end
|
data/lib/time_ext.rb
ADDED
data/spec/lexical_uuid_spec.rb
CHANGED
@@ -14,15 +14,11 @@ describe "LexicalUUID" do
|
|
14
14
|
@uuid.timestamp.should < Time.stamp
|
15
15
|
end
|
16
16
|
|
17
|
-
it "has jitter" do
|
18
|
-
@uuid.jitter.should_not be_nil
|
19
|
-
end
|
20
|
-
|
21
17
|
it "serializes to bytes" do
|
22
18
|
expected_bytes = [@uuid.timestamp >> 32,
|
23
19
|
@uuid.timestamp & 0xffffffff,
|
24
|
-
@uuid.
|
25
|
-
@uuid.worker_id].pack("
|
20
|
+
@uuid.worker_id >> 32,
|
21
|
+
@uuid.worker_id & 0xffffffff].pack("NNNN")
|
26
22
|
@uuid.to_bytes.should == expected_bytes
|
27
23
|
end
|
28
24
|
end
|
@@ -32,8 +28,8 @@ describe "LexicalUUID" do
|
|
32
28
|
before do
|
33
29
|
@bytes = [1234567890 >> 32,
|
34
30
|
1234567890 & 0xffffffff,
|
35
|
-
|
36
|
-
|
31
|
+
9876543210 >> 32,
|
32
|
+
9876543210 & 0xffffffff].pack("NNNN")
|
37
33
|
@uuid = LexicalUUID.new(@bytes)
|
38
34
|
end
|
39
35
|
|
@@ -41,12 +37,8 @@ describe "LexicalUUID" do
|
|
41
37
|
@uuid.timestamp.should == 1234567890
|
42
38
|
end
|
43
39
|
|
44
|
-
it "correctly extracts the jitter" do
|
45
|
-
@uuid.jitter.should == 54321
|
46
|
-
end
|
47
|
-
|
48
40
|
it "correctly extracts the worker id" do
|
49
|
-
@uuid.worker_id.should ==
|
41
|
+
@uuid.worker_id.should == 9876543210
|
50
42
|
end
|
51
43
|
end
|
52
44
|
|
@@ -62,9 +54,8 @@ describe "LexicalUUID" do
|
|
62
54
|
describe "initializing a uuid from a timestamp and worker_id" do
|
63
55
|
before do
|
64
56
|
@timestamp = 15463021018891620831
|
65
|
-
@
|
66
|
-
@
|
67
|
-
@uuid = LexicalUUID.new(@timestamp, @jitter, @worker_id)
|
57
|
+
@worker_id = 9964740229835689317
|
58
|
+
@uuid = LexicalUUID.new(@timestamp, @worker_id)
|
68
59
|
end
|
69
60
|
|
70
61
|
it "sets the timestamp" do
|
@@ -74,37 +65,29 @@ describe "LexicalUUID" do
|
|
74
65
|
it "sets the worker_id" do
|
75
66
|
@uuid.worker_id.should == @worker_id
|
76
67
|
end
|
77
|
-
|
78
|
-
it "sets the jitter" do
|
79
|
-
@uuid.jitter.should == @jitter
|
80
|
-
end
|
81
68
|
end
|
82
69
|
|
83
70
|
describe "converting a uuid in to a guid" do
|
84
71
|
before do
|
85
|
-
@uuid = LexicalUUID.new(15463021018891620831,
|
72
|
+
@uuid = LexicalUUID.new(15463021018891620831, 9964740229835689317)
|
86
73
|
end
|
87
74
|
|
88
75
|
it "matches other uuid->guid implementations" do
|
89
|
-
@uuid.to_guid.should == "
|
76
|
+
@uuid.to_guid.should == "d697afb0-a96f-11df-8a49-de718e668d65"
|
90
77
|
end
|
91
78
|
end
|
92
79
|
|
93
80
|
describe "initializing from a guid" do
|
94
81
|
before do
|
95
|
-
@uuid = LexicalUUID.new("
|
82
|
+
@uuid = LexicalUUID.new("d697afb0-a96f-11df-8a49-de718e668d65")
|
96
83
|
end
|
97
84
|
|
98
85
|
it "correctly initializes the timestamp" do
|
99
|
-
@uuid.timestamp.should ==
|
100
|
-
end
|
101
|
-
|
102
|
-
it "correctly initializes the jitter" do
|
103
|
-
@uuid.jitter.should == -2110931607
|
86
|
+
@uuid.timestamp.should == 15463021018891620831
|
104
87
|
end
|
105
88
|
|
106
89
|
it "correctly initializes the worker_id" do
|
107
|
-
@uuid.worker_id.should ==
|
90
|
+
@uuid.worker_id.should == 9964740229835689317
|
108
91
|
end
|
109
92
|
end
|
110
93
|
|
@@ -120,10 +103,6 @@ describe "LexicalUUID" do
|
|
120
103
|
it "uses the default worker_id" do
|
121
104
|
@uuid.worker_id.should == LexicalUUID.worker_id
|
122
105
|
end
|
123
|
-
|
124
|
-
it "initializes the jitter" do
|
125
|
-
@uuid.jitter.should_not be_nil
|
126
|
-
end
|
127
106
|
end
|
128
107
|
|
129
108
|
describe "comparing uuids" do
|
@@ -132,17 +111,11 @@ describe "LexicalUUID" do
|
|
132
111
|
(LexicalUUID.new(223) <=> LexicalUUID.new(134)).should == 1
|
133
112
|
end
|
134
113
|
|
135
|
-
it "compares by
|
114
|
+
it "compares by worker_id if the timestamps are equal" do
|
136
115
|
(LexicalUUID.new(123, 1) <=> LexicalUUID.new(123, 2)).should == -1
|
137
116
|
(LexicalUUID.new(123, 2) <=> LexicalUUID.new(123, 1)).should == 1
|
138
117
|
(LexicalUUID.new(123, 1) <=> LexicalUUID.new(123, 1)).should == 0
|
139
118
|
end
|
140
|
-
|
141
|
-
it "compares by worker_id if the timestamps and jitter are equal" do
|
142
|
-
(LexicalUUID.new(123, 1, 0) <=> LexicalUUID.new(123, 1, 1)).should == -1
|
143
|
-
(LexicalUUID.new(123, 1, 1) <=> LexicalUUID.new(123, 1, 0)).should == 1
|
144
|
-
(LexicalUUID.new(123, 1, 1) <=> LexicalUUID.new(123, 1, 1)).should == 0
|
145
|
-
end
|
146
119
|
end
|
147
120
|
|
148
121
|
describe "==" do
|
@@ -155,7 +128,7 @@ describe "LexicalUUID" do
|
|
155
128
|
end
|
156
129
|
|
157
130
|
it "is not equal when the worker_ids are not equal" do
|
158
|
-
LexicalUUID.new(123, 223
|
131
|
+
LexicalUUID.new(123, 223).should_not == LexicalUUID.new(123, 123)
|
159
132
|
end
|
160
133
|
end
|
161
134
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lexical_uuid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- James Golick
|
@@ -34,19 +34,17 @@ dependencies:
|
|
34
34
|
type: :development
|
35
35
|
version_requirements: *id001
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
|
-
name:
|
37
|
+
name: fnv
|
38
38
|
prerelease: false
|
39
39
|
requirement: &id002 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
|
-
- - "
|
42
|
+
- - ">="
|
43
43
|
- !ruby/object:Gem::Version
|
44
|
-
hash:
|
44
|
+
hash: 3
|
45
45
|
segments:
|
46
|
-
-
|
47
|
-
|
48
|
-
- 4
|
49
|
-
version: 3.8.4
|
46
|
+
- 0
|
47
|
+
version: "0"
|
50
48
|
type: :runtime
|
51
49
|
version_requirements: *id002
|
52
50
|
description: UUIDs that are byte-ordered lamport clocks (timestamp, worker_id). Much simpler than type-1 UUID's crappy, weirdo layout.
|
@@ -65,7 +63,9 @@ files:
|
|
65
63
|
- Rakefile
|
66
64
|
- VERSION
|
67
65
|
- lexical_uuid.gemspec
|
66
|
+
- lib/increasing_microsecond_clock.rb
|
68
67
|
- lib/lexical_uuid.rb
|
68
|
+
- lib/time_ext.rb
|
69
69
|
- spec/lexical_uuid_spec.rb
|
70
70
|
- spec/spec.opts
|
71
71
|
- spec/spec_helper.rb
|