lexical_uuid 0.1.7 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|