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 +1 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +39 -0
- data/Rakefile +5 -0
- data/exedb.gemspec +23 -0
- data/lib/exedb/version.rb +3 -0
- data/lib/exedb.rb +101 -0
- data/spec/exedb_spec.rb +76 -0
- metadata +89 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg/
|
data/Gemfile
ADDED
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
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
|
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
|
data/spec/exedb_spec.rb
ADDED
@@ -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:
|