exedb 0.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.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Sergey Zhumatiy
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ Exedb
2
+ -----
3
+
4
+ This is simple Ruby class, which implements
5
+ database-like interface for executables.
6
+
7
+ For example:
8
+
9
+ ```ruby
10
+ e=Exedb.new("my_long_working_exe arg1 arg2")
11
+ e.cache_timeout=10 # 10 seconds timeout
12
+
13
+ e.get # run and return exe output
14
+ e.get # just return exe output again!
15
+ sleep 10
16
+ e.get # run exe again (cache is timed out)
17
+ e.update # run exe and update cache NOW!
18
+ ```
19
+
20
+ If another program is running another instance on the
21
+ same Exedb it will wait for first one finish.
22
+
23
+
24
+ Methods and constants
25
+ ---------------------
26
+
27
+ - ::new(str=nil) - create new instance, str=exec line
28
+ - ::DEF_DIR - default dir for cache files
29
+ - ::DEF_CACHE_TIMEOUT - default cache timeout
30
+
31
+ - \#get - get exe output
32
+ - \#update - run exe anyway, return output
33
+
34
+ Accessors
35
+ --------
36
+
37
+ - cache_timeout
38
+ - cache_dir
39
+
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require 'rake/testtask'
2
+ Rake::TestTask.new do |t|
3
+ t.pattern = "spec/*_spec.rb"
4
+ end
5
+ require "bundler/gem_tasks"
data/exedb.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'exedb/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "exedb"
8
+ spec.version = Exedb::VERSION
9
+ spec.authors = ["Sergey Zhumatiy"]
10
+ spec.email = ["serg@parallel.ru"]
11
+ spec.summary = %q{Quazi-database for executables.}
12
+ spec.description = %q{Database-like interface to execute long tasks. With caching.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,3 @@
1
+ class Exedb
2
+ VERSION = "0.0.1"
3
+ end
data/lib/exedb.rb ADDED
@@ -0,0 +1,101 @@
1
+ require 'digest'
2
+ require 'time'
3
+
4
+ class Exedb
5
+
6
+ SLEEP_TIME=1
7
+ DEF_DIR='/tmp/Exedb'
8
+ DEF_CACHE_TIMEOUT=60
9
+
10
+ attr_accessor :cache_timeout, :cache_dir
11
+ attr_reader :update_time
12
+
13
+ def initialize(str=nil)
14
+ @update_time=Time.parse("1970-01-01")
15
+ @cache_timeout=DEF_CACHE_TIMEOUT
16
+ @cache_dir=DEF_DIR
17
+ Dir.mkdir DEF_DIR unless File.directory? DEF_DIR
18
+ update_method=str
19
+ end
20
+
21
+ def generate_key u
22
+ return Digest::SHA256.hexdigest u
23
+ end
24
+
25
+ def update
26
+ File.open(@path, File::RDWR|File::CREAT, 0644) { |file|
27
+ if file.flock(File::LOCK_EX|File::LOCK_NB)
28
+ @content=`#{@update_method}`
29
+ file.write @content
30
+ file.flush
31
+ file.flock(File::LOCK_UN)
32
+ else
33
+ read_cache
34
+ end
35
+ @update_time=Time.now
36
+ }
37
+ #!!!warn "UPDATED!'"
38
+ @content
39
+ end
40
+
41
+ def update_method= str
42
+ @update_method=str
43
+ @key=generate_key str
44
+ @path=File.join DEF_DIR, @key
45
+ end
46
+
47
+ def read_cache
48
+ File.open(@path, File::RDONLY) { |file|
49
+ file.flock(File::LOCK_EX)
50
+ @content=file.read
51
+ file.flock(File::LOCK_UN)
52
+ }
53
+ end
54
+
55
+ def get
56
+ state=cache_state
57
+ #warn "CACHED: #{state}"
58
+ case state
59
+ when :need_update
60
+ update
61
+ when :need_reread
62
+ #!!!warn "read cached"
63
+ read_cache
64
+ end
65
+ @content
66
+ end
67
+
68
+ # def get
69
+ # return get_cached
70
+ # #warn "Get: #{@update_time}+#{@cache_timeout}>#{Time.now}"
71
+ # if @update_time+@cache_timeout>Time.now
72
+ # # not need to update cache
73
+ # get_cached
74
+ # else
75
+ # update
76
+ # end
77
+ # end
78
+
79
+ def cache_state
80
+ if File.exists? @path
81
+ mtime=File.mtime(@path)
82
+ return :need_update if mtime+@cache_timeout<Time.now
83
+ return :need_reread if @update_time<mtime
84
+ return :updated
85
+ end
86
+ :need_update
87
+ end
88
+
89
+ def update_in_progress?
90
+ if File.exists? @path
91
+ File.open(@path, File::RDONLY) { |file|
92
+ if file.flock(File::LOCK_EX|File::LOCK_NB)
93
+ file.flock(File::LOCK_UN)
94
+ return false
95
+ end
96
+ }
97
+ return true
98
+ end
99
+ return false
100
+ end
101
+ end
@@ -0,0 +1,76 @@
1
+ require 'minitest/autorun'
2
+ require "exedb"
3
+
4
+ TEST_DIR='/tmp/exedb_test'
5
+ TEST_FILE='abc_file'
6
+ TEST_FILE2='efg_file'
7
+
8
+ describe Exedb do
9
+ before do
10
+ # clean up...
11
+ FileUtils.rm_rf Exedb::DEF_DIR
12
+
13
+ @db=Exedb.new
14
+ FileUtils.rm_rf TEST_DIR
15
+ Dir.mkdir TEST_DIR
16
+ File.open(File.join(TEST_DIR,TEST_FILE), "w") { |io| io.puts "ok" }
17
+
18
+ @db.update_method="sleep 1;ls -la #{TEST_DIR}"
19
+ end
20
+
21
+ it 'do update by default' do
22
+ @db.get.must_match TEST_FILE
23
+ end
24
+
25
+ it 'updates state' do
26
+ File.open(File.join(TEST_DIR,TEST_FILE2), "w") { |io| io.puts "ok" }
27
+ @db.update
28
+ @db.get.must_match TEST_FILE2
29
+ end
30
+
31
+ describe 'cache' do
32
+ before do
33
+ @db.update
34
+ File.open(File.join(TEST_DIR,TEST_FILE2), "w") { |io| io.puts "ok" }
35
+ end
36
+ it 'caches last result' do
37
+ @db.get.wont_match TEST_FILE2
38
+ end
39
+
40
+ it 'updates cache' do
41
+ @db.update
42
+ @db.get.must_match TEST_FILE2
43
+ end
44
+ end
45
+
46
+ describe 'parallel istances' do
47
+ before do
48
+ #!!!warn "BEFORE 2>>>>>>>"
49
+ @db2=Exedb.new
50
+ @db2.update_method="sleep 1;ls -la #{TEST_DIR}"
51
+ @db.update
52
+ end
53
+
54
+ it 'reads last cached result' do
55
+ sleep 2;
56
+ #!!!warn ">>>>>>>>>>>>>>>>>>"
57
+ @db2.get.must_match TEST_FILE
58
+ end
59
+
60
+ it 'not updates cache second time' do
61
+ sleep 2;
62
+ @time=Time.now
63
+ @db2.get
64
+ (Time.now-@time).must_be :<, 0.1
65
+ end
66
+
67
+ it 'updates cache after timeout' do
68
+ @db2.cache_timeout=3
69
+ sleep 4;
70
+ @time=Time.now
71
+ @db2.get
72
+ (Time.now-@time).must_be :>, 1
73
+ end
74
+ end
75
+
76
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: exedb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sergey Zhumatiy
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-01-31 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.5'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.5'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Database-like interface to execute long tasks. With caching.
47
+ email:
48
+ - serg@parallel.ru
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - Gemfile
55
+ - LICENSE.txt
56
+ - README.md
57
+ - Rakefile
58
+ - exedb.gemspec
59
+ - lib/exedb.rb
60
+ - lib/exedb/version.rb
61
+ - spec/exedb_spec.rb
62
+ homepage: ''
63
+ licenses:
64
+ - MIT
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 1.8.23
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Quazi-database for executables.
87
+ test_files:
88
+ - spec/exedb_spec.rb
89
+ has_rdoc: