onliest 0.0.2 → 0.1.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.
- checksums.yaml +4 -4
- data/lib/onliest/snowflake.rb +42 -0
- data/lib/onliest.rb +16 -11
- data/test/{test_onliest.rb → test_onliest_default.rb} +9 -14
- data/test/test_onliest_snowflake.rb +54 -0
- metadata +41 -33
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -4
- metadata.gz.sig +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: efb038a4ae13fe3e96144555528df22c58069f09
|
4
|
+
data.tar.gz: 253159af40687da8125e46543ffbdf28a95cb646
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3ad14aebd918aabb5b046f4b769220ed41fa4f668371b84126e084ca6522d98f47d109adf0099af6a426610bdb99ba5b23f8f67e23e5e7b9d1a555e67160df2
|
7
|
+
data.tar.gz: 976cc81e29400a059d515b6406ceb17ce6d55a10463b839d1128ab1a21eb71325b92eb3895f6fd67fa855a352a250fed769427a8e191acb331c2bdaea504b137
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'onliest'
|
2
|
+
|
3
|
+
class Onliest::Snowflake < Onliest
|
4
|
+
attr_reader :worker_number, :sequence
|
5
|
+
|
6
|
+
# This comes from twitter snowflake. I'm not
|
7
|
+
# sure how they arrived at this number.
|
8
|
+
# November 3, 2010 at 11:42:55
|
9
|
+
EPOCH = 1288834974657
|
10
|
+
|
11
|
+
def initialize(worker_number)
|
12
|
+
@worker_number = worker_number
|
13
|
+
@sequence = 0
|
14
|
+
@older_time = 0
|
15
|
+
super(fields: [{ bits: 1, generator: ->{ 0 } },
|
16
|
+
{ bits: 41, generator: ->{ time } },
|
17
|
+
{ bits: 10, generator: ->{ worker_number } },
|
18
|
+
{ bits: 12, generator: ->{ sequence_nextval } }])
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def sequence_nextval
|
24
|
+
i = @sequence
|
25
|
+
@sequence = @sequence.succ
|
26
|
+
i
|
27
|
+
end
|
28
|
+
|
29
|
+
def time
|
30
|
+
while (t = time_now) < @older_time
|
31
|
+
#puts @older_time
|
32
|
+
#puts t
|
33
|
+
sleep((@older_time - t) / 1000)
|
34
|
+
end
|
35
|
+
@older_time = t
|
36
|
+
t
|
37
|
+
end
|
38
|
+
|
39
|
+
def time_now
|
40
|
+
((Time.now.to_f * 1000).to_i - EPOCH)
|
41
|
+
end
|
42
|
+
end
|
data/lib/onliest.rb
CHANGED
@@ -24,23 +24,28 @@ class Onliest
|
|
24
24
|
# +SecureRandom+. An object that implements +:random_number+
|
25
25
|
# returning a random integer >= 0 and less than value provided as
|
26
26
|
# the first argument.
|
27
|
-
def initialize(rng
|
28
|
-
@
|
27
|
+
def initialize(rng: DEFAULT_RNG, fields: false)
|
28
|
+
@fields = fields ? fields : default_fields(rng)
|
29
29
|
end
|
30
30
|
|
31
|
-
#
|
31
|
+
# Construct and return the unique value
|
32
32
|
def value
|
33
|
-
|
34
|
-
|
33
|
+
total_bits = 0
|
34
|
+
total_value = 0
|
35
|
+
@fields.reverse.each do |field|
|
36
|
+
bits = field.fetch(:bits)
|
37
|
+
field_value = Integer(field.fetch(:generator).call) & ((2**bits) - 1)
|
38
|
+
total_value += (field_value << total_bits)
|
39
|
+
total_bits += bits
|
40
|
+
end
|
41
|
+
total_value
|
35
42
|
end
|
36
43
|
|
37
44
|
private
|
38
45
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
def some_time_bits
|
44
|
-
Time.now.to_i & TIME_BITMASK
|
46
|
+
def default_fields(rng)
|
47
|
+
[{ bits: TIME_BITS, generator: -> { Time.now.to_i } },
|
48
|
+
{ bits: RANDOM_BITS,
|
49
|
+
generator: -> { rng.random_number(RANDOM_BITMASK + 1) } }]
|
45
50
|
end
|
46
51
|
end
|
@@ -1,8 +1,9 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative './test_setup'
|
3
2
|
require 'onliest'
|
4
3
|
|
5
|
-
|
4
|
+
# Tests for the dkjefault scheme
|
5
|
+
|
6
|
+
class OnliestDefaultTest < TestCase
|
6
7
|
def test_generates_a_number
|
7
8
|
assert_kind_of(Integer, Onliest.value)
|
8
9
|
end
|
@@ -16,31 +17,25 @@ class OnliestTest < Minitest::Unit::TestCase
|
|
16
17
|
fake_prng.expect(:random_number, value, [2**47])
|
17
18
|
end
|
18
19
|
|
19
|
-
def at(value)
|
20
|
-
Time.stub(:now, Time.at(value)) do
|
21
|
-
yield
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
20
|
def test_with_a_time_and_a_prng
|
26
21
|
at((2**25) + 1) do
|
27
22
|
random_value = 2
|
28
|
-
gen = Onliest.new(fake_prng(random_value))
|
29
|
-
assert_equal(
|
23
|
+
gen = Onliest.new(rng: fake_prng(random_value))
|
24
|
+
assert_equal((1 << 47) + random_value, gen.value)
|
30
25
|
end
|
31
26
|
end
|
32
27
|
|
33
28
|
def test_the_littlest_onliest
|
34
29
|
at(0) do
|
35
|
-
gen = Onliest.new(fake_prng(0))
|
30
|
+
gen = Onliest.new(rng: fake_prng(0))
|
36
31
|
assert_equal(gen.value, 0)
|
37
32
|
end
|
38
33
|
end
|
39
34
|
|
40
35
|
def test_the_largest_onliest
|
41
36
|
at(2**25 - 1) do
|
42
|
-
gen = Onliest.new(fake_prng(2**47 - 1))
|
43
|
-
assert_equal(
|
37
|
+
gen = Onliest.new(rng: fake_prng(2**47 - 1))
|
38
|
+
assert_equal(2**72 - 1, gen.value)
|
44
39
|
end
|
45
40
|
end
|
46
41
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require_relative './test_setup'
|
2
|
+
require 'onliest/snowflake'
|
3
|
+
|
4
|
+
class SnowflakeTests < TestCase
|
5
|
+
def worker_number
|
6
|
+
'13'
|
7
|
+
end
|
8
|
+
|
9
|
+
def generator
|
10
|
+
Onliest::Snowflake.new(worker_number)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_snowflake_sign_bit_is_zero
|
14
|
+
assert_equal(0, generator.value & (1 << 63))
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_snowflake_time_with_millisecond_precision
|
18
|
+
at(1.1234 + (Onliest::Snowflake::EPOCH.to_f / 1000)) do
|
19
|
+
assert_equal(1123, generator.value >> 22)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_snowflake_worker_number
|
24
|
+
assert_equal(worker_number.to_i, (generator.value & (2**22 - 1)) >> 12)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_snowflake_sequence_starts_at_zero
|
28
|
+
assert_equal(0, generator.value & ((2**12 - 1)))
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_snowflake_sequence_increments
|
32
|
+
at(Time.now.to_i) do
|
33
|
+
gen = generator
|
34
|
+
assert_equal(gen.value, gen.value - 1)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_snowflake_epoch_starts_at_1288834974_657
|
39
|
+
at(1288834974657.to_f / 1000) do
|
40
|
+
assert_equal(0, generator.value >> 22)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_time_always_goes_forward
|
45
|
+
gen = generator
|
46
|
+
times = [Onliest::Snowflake::EPOCH + 0.10,
|
47
|
+
Onliest::Snowflake::EPOCH,
|
48
|
+
Onliest::Snowflake::EPOCH + 0.11]
|
49
|
+
|
50
|
+
Time.stub(:now, ->{ times.shift } ) do
|
51
|
+
assert(gen.value < gen.value)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
metadata
CHANGED
@@ -1,37 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: onliest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Church
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
|
-
cert_chain:
|
11
|
-
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5'
|
35
41
|
description: Generate unique values with numeric locality.
|
36
42
|
email: chrchr@gmail.com
|
37
43
|
executables:
|
@@ -39,9 +45,11 @@ executables:
|
|
39
45
|
extensions: []
|
40
46
|
extra_rdoc_files: []
|
41
47
|
files:
|
42
|
-
- lib/onliest.rb
|
43
48
|
- bin/onliest
|
44
|
-
-
|
49
|
+
- lib/onliest.rb
|
50
|
+
- lib/onliest/snowflake.rb
|
51
|
+
- test/test_onliest_default.rb
|
52
|
+
- test/test_onliest_snowflake.rb
|
45
53
|
homepage: https://github.com/chrchr/onliest
|
46
54
|
licenses:
|
47
55
|
- MIT
|
@@ -52,20 +60,20 @@ require_paths:
|
|
52
60
|
- lib
|
53
61
|
required_ruby_version: !ruby/object:Gem::Requirement
|
54
62
|
requirements:
|
55
|
-
- -
|
63
|
+
- - ">="
|
56
64
|
- !ruby/object:Gem::Version
|
57
65
|
version: '0'
|
58
66
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
67
|
requirements:
|
60
|
-
- -
|
68
|
+
- - ">="
|
61
69
|
- !ruby/object:Gem::Version
|
62
70
|
version: '0'
|
63
71
|
requirements: []
|
64
72
|
rubyforge_project:
|
65
|
-
rubygems_version: 2.
|
73
|
+
rubygems_version: 2.4.5
|
66
74
|
signing_key:
|
67
75
|
specification_version: 4
|
68
76
|
summary: 'Onliest: generate unique values with numeric locality'
|
69
77
|
test_files:
|
70
|
-
- test/
|
71
|
-
|
78
|
+
- test/test_onliest_default.rb
|
79
|
+
- test/test_onliest_snowflake.rb
|
checksums.yaml.gz.sig
DELETED
Binary file
|
data.tar.gz.sig
DELETED
metadata.gz.sig
DELETED