redis_int64_autoincrement 1.0.1
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 +7 -0
- data/CHANGELOG +2 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +41 -0
- data/Rakefile +41 -0
- data/lib/redis_int64_autoincrement.rb +56 -0
- data/redis_int64_autoincrement.gemspec +20 -0
- data/test/test_redis_int64_autoincrement.rb +19 -0
- metadata +59 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2bbc26b02afa193c0e2947e4542f815dfc87deeb8c287f0e1247734b1da0e5bb
|
4
|
+
data.tar.gz: 89c192e8a7fe00c6f4fbda5820d994221fb43aab64c40f85e92aa0d45dc9b806
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cce355500385c72b4415a7c92476b0e06b19b4a82b32ee0085373464f3d2ec3f8cc3d24cc55065447990a895b1bcda5d1f85b1e7fbba4384c2e0fcf914014552
|
7
|
+
data.tar.gz: 52cf55f161551a6ae30ec71338acae604a956e41a0ebf272c1291aa625ce934b76c6cb00eefdea7c820440e75f320c31ee70f16b6994a1ac53afa0a7908549cc
|
data/CHANGELOG
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2023-2024 Andrew Chernuha
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
= Int64 UUID (UInt64, UInt63) autoincremented via redis-server
|
2
|
+
|
3
|
+
Generates universally unique identifiers (UUID64) with unsigned Int64 (so it will be UInt63)
|
4
|
+
for use in distributed applications.
|
5
|
+
Based on:
|
6
|
+
1) possibility autoincrement value in redis-server
|
7
|
+
2) unix timestamps with microseconds
|
8
|
+
3) expire key possibility in redis database.
|
9
|
+
|
10
|
+
|
11
|
+
== Generating UInt63 Ids
|
12
|
+
|
13
|
+
Call #generate to generate a new UUID64. The method returns a Int64 unique value.
|
14
|
+
|
15
|
+
For example in rails:
|
16
|
+
|
17
|
+
before_create do |record|
|
18
|
+
record.id ||= RedisInt64Autoincrement.generate(Rails.cache.redis || Redis.new(url: "redis://localhost:6379/0"))
|
19
|
+
end
|
20
|
+
|
21
|
+
== Why so hard?
|
22
|
+
|
23
|
+
We have an issue where the servers have different times on each server and during the time the server syncs the time we have a shift of a few seconds.
|
24
|
+
So this lib have +-50(UUID64_MAX_SECONDS_EXPIRE) seconds maximum for delta shift.
|
25
|
+
|
26
|
+
== Latest and Greatest
|
27
|
+
|
28
|
+
Source code and documentation hosted on Github: http://github.com/trumenov/redis_int64_autoincrement
|
29
|
+
|
30
|
+
To get UUID64 from source:
|
31
|
+
|
32
|
+
git clone git://github.com/trumenov/redis_int64_autoincrement.git
|
33
|
+
|
34
|
+
|
35
|
+
== License
|
36
|
+
|
37
|
+
This package is licensed under the MIT license and/or the Creative
|
38
|
+
Commons Attribution-ShareAlike.
|
39
|
+
|
40
|
+
:include: MIT-LICENSE
|
41
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
#require 'rake/rdoctask'
|
3
|
+
|
4
|
+
|
5
|
+
spec = Gem::Specification.load(File.expand_path("redis_int64_autoincrement.gemspec", File.dirname(__FILE__)))
|
6
|
+
|
7
|
+
desc "Default Task"
|
8
|
+
task :default => :test
|
9
|
+
|
10
|
+
|
11
|
+
desc "Run all test cases"
|
12
|
+
Rake::TestTask.new do |test|
|
13
|
+
test.verbose = true
|
14
|
+
test.test_files = ['test/*.rb']
|
15
|
+
test.warning = true
|
16
|
+
end
|
17
|
+
|
18
|
+
# Create the documentation.
|
19
|
+
#Rake::RDocTask.new do |rdoc|
|
20
|
+
# rdoc.rdoc_files.include "README.rdoc", "lib/**/*.rb"
|
21
|
+
# rdoc.options = spec.rdoc_options
|
22
|
+
#end
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
desc "Push new release to rubyforge and git tag"
|
27
|
+
task :push do
|
28
|
+
sh "git push"
|
29
|
+
puts "Tagging version #{spec.version} .."
|
30
|
+
sh "git tag v#{spec.version}"
|
31
|
+
sh "git push --tag"
|
32
|
+
puts "Building and pushing gem .."
|
33
|
+
sh "gem build #{spec.name}.gemspec"
|
34
|
+
sh "gem push #{spec.name}-#{spec.version}.gem"
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "Install #{spec.name} locally"
|
38
|
+
task :install do
|
39
|
+
sh "gem build #{spec.name}.gemspec"
|
40
|
+
sh "gem install #{spec.name}-#{spec.version}.gem"
|
41
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class RedisInt64Autoincrement
|
2
|
+
|
3
|
+
# Why 50 seconds? Easy to debug and more than enouth for sync time delta shift.
|
4
|
+
# You can use 10 or 5 seconds - and all must working normal too.
|
5
|
+
# 50seconds was chosen by me without any explanation. Just took this value, i do not know why.
|
6
|
+
REDIS_KEY_TTL_SECONDS = 50
|
7
|
+
|
8
|
+
MAX_BUFFER_BITS_CNT = 63 # Do not use all 64 bits - in this case signed Int64 can be less than result uid
|
9
|
+
TIMESTAMP_BITS_CNT = 34.freeze # 34bits for 150+ years more than enougth
|
10
|
+
TIMESTAMP_MICROSECONDS_BITS_CNT = 20.freeze # 0..999_999 - require 20bits
|
11
|
+
INCREMENTED_ID_BITS_CNT = 7.freeze # 7bits for 0..127 INCREMENTED_UINT8_ID
|
12
|
+
SERVER_ID_BITS_CNT = 2.freeze
|
13
|
+
# So in result: 34 + 20 + 7 + 2 = 63bits(MAX_BUFFER_BITS_CNT).
|
14
|
+
|
15
|
+
TIMESTAMP_SECONDS_SHIFT_LEFT_CNT = (TIMESTAMP_MICROSECONDS_BITS_CNT + INCREMENTED_ID_BITS_CNT + SERVER_ID_BITS_CNT).freeze # 29 bits
|
16
|
+
TIMESTAMP_MICROSECONDS_SHIFT_LEFT_CNT = (INCREMENTED_ID_BITS_CNT + SERVER_ID_BITS_CNT).freeze # 9 bits
|
17
|
+
INCREMENTED_ID_MAX_VAL = ((1 << INCREMENTED_ID_BITS_CNT) - 1).freeze # 1111111b=127
|
18
|
+
UINT63_MAX_VAL = 9223372036854775808 # 2^63 = 9223372036854775808
|
19
|
+
LIB_FIRST_VAL = 914476352027817480 # First id was generated 23.12.2023 at ~17:30 (Kiev +2:00)
|
20
|
+
|
21
|
+
# Version number.
|
22
|
+
module Version
|
23
|
+
version = Gem::Specification.load(File.expand_path("../redis_int64_autoincrement.gemspec", File.dirname(__FILE__))).version.to_s.split(".").map { |i| i.to_i }
|
24
|
+
MAJOR = version[1]
|
25
|
+
MINOR = version[0]
|
26
|
+
PATCH = version[1]
|
27
|
+
STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
|
28
|
+
end
|
29
|
+
|
30
|
+
VERSION = Version::STRING
|
31
|
+
|
32
|
+
class << self
|
33
|
+
def generate(redis, namespace = 'default', options = {})
|
34
|
+
server_id = options[:server_id] || 0
|
35
|
+
time_redis = options[:time_redis] || redis
|
36
|
+
raise("Wrong server_id[#{server_id}]. Allow only 0..3 server_id") unless server_id.between?(0, 3)
|
37
|
+
time_arr = time_redis.time
|
38
|
+
raise("Wrong time type[#{time_arr.inspect}]") unless time_arr.count.eql?(2)
|
39
|
+
unix_seconds = time_arr.first.to_i
|
40
|
+
first_part = unix_seconds << TIMESTAMP_SECONDS_SHIFT_LEFT_CNT
|
41
|
+
|
42
|
+
microseconds = time_arr[1].to_i
|
43
|
+
raise("Wrong microseconds [#{microseconds}]") unless microseconds.between?(0, 999_999)
|
44
|
+
second_part = microseconds << TIMESTAMP_MICROSECONDS_SHIFT_LEFT_CNT
|
45
|
+
|
46
|
+
key = "ai64:#{namespace}:#{unix_seconds}:#{microseconds}"
|
47
|
+
incremented_val = redis.incrby(key, 1)
|
48
|
+
redis.expire(key, REDIS_KEY_TTL_SECONDS)
|
49
|
+
raise("Wrong incremented_val [#{incremented_val}]") unless incremented_val.between?(0, INCREMENTED_ID_MAX_VAL)
|
50
|
+
third_part = incremented_val << SERVER_ID_BITS_CNT
|
51
|
+
result = ((first_part | second_part) | third_part) | server_id
|
52
|
+
raise("Wrong result[#{result}]") unless result.between?(LIB_FIRST_VAL, UINT63_MAX_VAL)
|
53
|
+
result
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'redis_int64_autoincrement'
|
3
|
+
s.version = '1.0.1'
|
4
|
+
s.summary = "Int64 (UInt63) autoincrement via redis-servers"
|
5
|
+
s.description = <<-EOF
|
6
|
+
Int64 (UInt64, UInt63) autoincrement via redis-servers with timestamp in microseconds, autoincerent via redis key.
|
7
|
+
Support 1-5 redis servers in one system (1 - timestamp + 4 servers - autoincrementers).
|
8
|
+
EOF
|
9
|
+
|
10
|
+
s.authors << 'Trumenov' << 'Chaky'
|
11
|
+
s.email = 'chaky22222222@gmail.com'
|
12
|
+
s.homepage = 'http://github.com/trumenov/redis_int64_autoincrement'
|
13
|
+
s.license = 'MIT'
|
14
|
+
|
15
|
+
s.files = Dir['{bin,test,lib,docs}/**/*'] + ['README.rdoc', 'MIT-LICENSE', 'Rakefile', 'CHANGELOG', 'redis_int64_autoincrement.gemspec']
|
16
|
+
|
17
|
+
s.rdoc_options << '--main' << 'README.rdoc' << '--title' << 'Int64 redis autoincrementer' << '--line-numbers'
|
18
|
+
'--webcvs' << 'http://github.com/trumenov/redis_int64_autoincrement'
|
19
|
+
s.extra_rdoc_files = ['README.rdoc', 'MIT-LICENSE']
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# Author:: Andrew Chernuha chaky22222222@gmail.com
|
3
|
+
# License:: MIT and/or Creative Commons Attribution-ShareAlike
|
4
|
+
|
5
|
+
require 'test/unit'
|
6
|
+
require 'rubygems'
|
7
|
+
require 'redis_int64_autoincrement'
|
8
|
+
require "redis"
|
9
|
+
|
10
|
+
class TestRedisInt64Autoincrement < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def test_check_generated_placed_in_target_region
|
13
|
+
redis = Redis.new(url: "redis://localhost:6379/0")
|
14
|
+
left_part = Time.now.to_i << (RedisInt64Autoincrement::MAX_BUFFER_BITS_CNT - RedisInt64Autoincrement::TIMESTAMP_BITS_CNT)
|
15
|
+
new_id = RedisInt64Autoincrement.generate(redis)
|
16
|
+
right_part = (Time.now.to_i + 1) << (RedisInt64Autoincrement::MAX_BUFFER_BITS_CNT - RedisInt64Autoincrement::TIMESTAMP_BITS_CNT)
|
17
|
+
assert new_id.between?(left_part, right_part)
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redis_int64_autoincrement
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Trumenov
|
8
|
+
- Chaky
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2023-12-23 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: |
|
15
|
+
Int64 (UInt64, UInt63) autoincrement via redis-servers with timestamp in microseconds, autoincerent via redis key.
|
16
|
+
Support 1-5 redis servers in one system (1 - timestamp + 4 servers - autoincrementers).
|
17
|
+
email: chaky22222222@gmail.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files:
|
21
|
+
- README.rdoc
|
22
|
+
- MIT-LICENSE
|
23
|
+
files:
|
24
|
+
- CHANGELOG
|
25
|
+
- MIT-LICENSE
|
26
|
+
- README.rdoc
|
27
|
+
- Rakefile
|
28
|
+
- lib/redis_int64_autoincrement.rb
|
29
|
+
- redis_int64_autoincrement.gemspec
|
30
|
+
- test/test_redis_int64_autoincrement.rb
|
31
|
+
homepage: http://github.com/trumenov/redis_int64_autoincrement
|
32
|
+
licenses:
|
33
|
+
- MIT
|
34
|
+
metadata: {}
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options:
|
37
|
+
- "--main"
|
38
|
+
- README.rdoc
|
39
|
+
- "--title"
|
40
|
+
- Int64 redis autoincrementer
|
41
|
+
- "--line-numbers"
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
requirements: []
|
55
|
+
rubygems_version: 3.3.26
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: Int64 (UInt63) autoincrement via redis-servers
|
59
|
+
test_files: []
|