redis_int52_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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: be347a0e6721c196136980f15f5fcb895cb1770955795a7e802dcdb8d80a8f3a
4
+ data.tar.gz: 4d7ed637481c0369ef22d169f71a5a8f5c9bb230c662fc6910fd979d410e56f1
5
+ SHA512:
6
+ metadata.gz: 55b7e45781f9e8eafe092e9350e3a85c9c6198882fa94e7e222f7a8c6c2089d2a0ab891bc54c2d7daa09dd479fbb6edd6cf5f1d3553970ac9f567ee65ff4bb74
7
+ data.tar.gz: c0fb76237341a72b1ae47417c572499568a752c9122c0a56a8b4707082fcdbc0efa384cdc375a02ebae1fd1bf4f9d2ca8c149c40f8c2e698eb25aefafa10f3a5
data/CHANGELOG ADDED
@@ -0,0 +1,2 @@
1
+ 1.0.1 (2024-02-02)
2
+ Creted first version by AndrewTrumenov (chaky22222222@gmail.com).
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,60 @@
1
+ = Int64 UUID (UInt52) autoincremented via redis-server
2
+
3
+ Why UInt52? Becouse JavaScript have problems with usege of Int64 values, that less than UInt54 max value.
4
+ So I create this library for be sure that migration to the UUID64 will not brake front side with rounding JavaScript bug.
5
+
6
+ What bug? Please open in your browser console and put into it
7
+
8
+ 11111111111111111+2
9
+
10
+ What you see? Yes! It is 11111111111111114.
11
+
12
+ But it is not all. Please insert in this console 11111111111111111 and press enter. What you see? Yes, it is 11111111111111112.
13
+
14
+ Why it happens: becouse JavaScript use Double for store and working with Integers. Yes, i know, it is really bad idea :(.
15
+
16
+ So UInt54 is the maximum int that JavaScript can process without this bug.
17
+
18
+ If you do not want search and fix all places in your project with this bug and you need UUID64 - use this lib.
19
+
20
+ = What this gem provide:
21
+ Generates universally unique identifiers (UUID52) with unsigned Int64 last 52 bits (so it will be UInt52)
22
+ for use in distributed applications.
23
+ Based on:
24
+ 1) possibility autoincrement value in redis-server
25
+ 2) unix timestamps with microseconds
26
+ 3) expire key possibility in redis database.
27
+ 4) this value UInt52 can be used by JavaScript without lags.
28
+
29
+
30
+ == Generating UInt52 Ids
31
+
32
+ Call #generate to generate a new UUID64. The method returns a Int64 unique value less than UINT52 max value.
33
+
34
+ For example in rails:
35
+
36
+ before_create do |record|
37
+ record.id ||= RedisInt52Autoincrement.generate(Rails.cache.redis || Redis.new(url: "redis://localhost:6379/0"))
38
+ end
39
+
40
+ == Why so hard?
41
+
42
+ 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.
43
+ So this lib have +-50(UUID52_MAX_SECONDS_EXPIRE) seconds maximum for delta shift.
44
+
45
+ == Latest and Greatest
46
+
47
+ Source code and documentation hosted on Github: http://github.com/trumenov/redis_int52_autoincrement
48
+
49
+ To get UUID52 from source:
50
+
51
+ git clone git://github.com/trumenov/redis_int52_autoincrement.git
52
+
53
+
54
+ == License
55
+
56
+ This package is licensed under the MIT license and/or the Creative
57
+ Commons Attribution-ShareAlike.
58
+
59
+ :include: MIT-LICENSE
60
+
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_int52_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,58 @@
1
+ class RedisInt52Autoincrement
2
+
3
+ # Why 30 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
+ # 30seconds was chosen by me without any explanation. Just took this value, i do not know why.
6
+ REDIS_KEY_TTL_SECONDS = 30
7
+
8
+ MAX_BUFFER_BITS_CNT = 52
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
+ TIMESTAMP_MICROSECONDS_STORE_BITS_CNT = 9.freeze # from max value 999_999 we will take only first 9 high bits.
12
+ TIMESTAMP_MICROSECONDS_BITS_SHL = TIMESTAMP_MICROSECONDS_BITS_CNT - TIMESTAMP_MICROSECONDS_STORE_BITS_CNT
13
+ INCREMENTED_ID_BITS_CNT = 7.freeze # 7bits for 0..127 INCREMENTED_UINT8_ID
14
+ SERVER_ID_BITS_CNT = 2.freeze
15
+ # So in result: 34 + 9 + 7 + 2 = 52bits(MAX_BUFFER_BITS_CNT).
16
+
17
+ TIMESTAMP_SECONDS_SHIFT_LEFT_CNT = (TIMESTAMP_MICROSECONDS_STORE_BITS_CNT + INCREMENTED_ID_BITS_CNT + SERVER_ID_BITS_CNT).freeze # 18 bits
18
+ TIMESTAMP_MICROSECONDS_SHIFT_LEFT_CNT = (INCREMENTED_ID_BITS_CNT + SERVER_ID_BITS_CNT).freeze # 9 bits
19
+ INCREMENTED_ID_MAX_VAL = ((1 << INCREMENTED_ID_BITS_CNT) - 1).freeze # 1111111b=127
20
+ UINT52_MAX_VAL = 4503599627370496 # 2^52 = 4503599627370496
21
+ LIB_FIRST_VAL = 447450850315268 # First id was generated 02.02.2024 at ~18:00 (Kiev +2:00)
22
+
23
+ # Version number.
24
+ module Version
25
+ version = Gem::Specification.load(File.expand_path("../redis_int52_autoincrement.gemspec", File.dirname(__FILE__))).version.to_s.split(".").map { |i| i.to_i }
26
+ MAJOR = version[1]
27
+ MINOR = version[0]
28
+ PATCH = version[1]
29
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
30
+ end
31
+
32
+ VERSION = Version::STRING
33
+
34
+ class << self
35
+ def generate(redis, namespace = 'default', options = {})
36
+ server_id = options[:server_id] || 0
37
+ time_redis = options[:time_redis] || redis
38
+ raise("Wrong server_id[#{server_id}]. Allow only 0..3 server_id") unless server_id.between?(0, 3)
39
+ time_arr = time_redis.time
40
+ raise("Wrong time type[#{time_arr.inspect}]") unless time_arr.count.eql?(2)
41
+ unix_seconds = time_arr.first.to_i
42
+ first_part = unix_seconds << TIMESTAMP_SECONDS_SHIFT_LEFT_CNT
43
+
44
+ microseconds = time_arr[1].to_i
45
+ raise("Wrong microseconds [#{microseconds}]") unless microseconds.between?(0, 999_999)
46
+ second_part = (microseconds >> TIMESTAMP_MICROSECONDS_BITS_SHL) << TIMESTAMP_MICROSECONDS_SHIFT_LEFT_CNT
47
+
48
+ key = "ai64:#{namespace}:#{unix_seconds}:#{microseconds}"
49
+ incremented_val = redis.incrby(key, 1)
50
+ redis.expire(key, REDIS_KEY_TTL_SECONDS)
51
+ raise("Wrong incremented_val [#{incremented_val}]") unless incremented_val.between?(0, INCREMENTED_ID_MAX_VAL)
52
+ third_part = incremented_val << SERVER_ID_BITS_CNT
53
+ result = ((first_part | second_part) | third_part) | server_id
54
+ raise("Wrong result[#{result}]") unless result.between?(LIB_FIRST_VAL, UINT52_MAX_VAL)
55
+ result
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,20 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'redis_int52_autoincrement'
3
+ s.version = '1.0.1'
4
+ s.summary = "Int64 (UInt52) autoincrement via redis-servers"
5
+ s.description = <<-EOF
6
+ Int64 (UInt52) 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_int52_autoincrement'
13
+ s.license = 'MIT'
14
+
15
+ s.files = Dir['{bin,test,lib,docs}/**/*'] + ['README.rdoc', 'MIT-LICENSE', 'Rakefile', 'CHANGELOG', 'redis_int52_autoincrement.gemspec']
16
+
17
+ s.rdoc_options << '--main' << 'README.rdoc' << '--title' << 'Int64 UInt52 redis autoincrementer' << '--line-numbers'
18
+ '--webcvs' << 'http://github.com/trumenov/redis_int52_autoincrement'
19
+ s.extra_rdoc_files = ['README.rdoc', 'MIT-LICENSE']
20
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+ # Author:: Andrew Chernuha chaky22222222@gmail.com
3
+ # License:: MIT and/or Creative Commons Attribution-ShareAlike
4
+ # run test with command: rake
5
+
6
+ require 'test/unit'
7
+ require 'rubygems'
8
+ require 'redis_int52_autoincrement'
9
+ require "redis"
10
+
11
+ class TestRedisInt52Autoincrement < Test::Unit::TestCase
12
+
13
+ def test_check_generated_placed_in_target_region
14
+ redis = Redis.new(url: "redis://localhost:6379/0")
15
+ left_part = Time.now.to_i << (RedisInt52Autoincrement::MAX_BUFFER_BITS_CNT - RedisInt52Autoincrement::TIMESTAMP_BITS_CNT)
16
+ new_id = RedisInt52Autoincrement.generate(redis)
17
+ right_part = (Time.now.to_i + 1) << (RedisInt52Autoincrement::MAX_BUFFER_BITS_CNT - RedisInt52Autoincrement::TIMESTAMP_BITS_CNT)
18
+ assert new_id.between?(left_part, right_part)
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redis_int52_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: 2024-02-02 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: |
15
+ Int64 (UInt52) 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_int52_autoincrement.rb
29
+ - redis_int52_autoincrement.gemspec
30
+ - test/test_redis_int52_autoincrement.rb
31
+ homepage: http://github.com/trumenov/redis_int52_autoincrement
32
+ licenses:
33
+ - MIT
34
+ metadata: {}
35
+ post_install_message:
36
+ rdoc_options:
37
+ - "--main"
38
+ - README.rdoc
39
+ - "--title"
40
+ - Int64 UInt52 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 (UInt52) autoincrement via redis-servers
59
+ test_files: []