persistent-cache 0.4.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/README.md +3 -3
- data/lib/persistent-cache.rb +4 -4
- data/lib/persistent-cache/version.rb +1 -3
- data/persistent-cache.gemspec +11 -6
- data/spec/persistent-cache_spec.rb +0 -3
- data/spec/spec_helper.rb +5 -1
- data/spec/storage/storage_directory_spec.rb +0 -2
- data/spec/storage/storage_ram_spec.rb +0 -1
- data/spec/storage/storage_sqlite_spec.rb +0 -1
- metadata +70 -44
- data/.rvmrc +0 -48
- data/lib/persistent-cache/storage/storage_directory.rb +0 -170
- data/lib/persistent-cache/storage/storage_ram.rb +0 -51
- data/lib/persistent-cache/storage/storage_sq_lite.rb +0 -97
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1c8b77545d0f4b605d15137012b0fcaf1f849032
|
4
|
+
data.tar.gz: e2258f5db2125f20ca38253e8f6fd51065783aca
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6282dbd4b4916eedf1a97dbdb0d6f0a2c28422a7f6f0191c29e112b6a0b76e5daa42d22b2a0e8994b7eebce4333e877ec79fc8d8e927f9d9edd6985302ada000
|
7
|
+
data.tar.gz: 03eaed66ba58ca33230093b2b892be3f9bf889e354f610ebdd9e5a823f9fd816d1cb111c151e275101b45ba5dd680114100aed28f46a3e7350395f9ed581442a
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
persistent-cache
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.3.0
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@ Values in the cache have a default freshness period of 15465600 ms. This can be
|
|
6
6
|
|
7
7
|
Note that when using a back-end that requires marshalling (e.g. sqlite) the string encoding for []= and [] needs to be the same (e.g. UTF-8, US-ASCII, etc.) If the coding does not match, [] will not be able to find the entry during lookup and will return nil. See the section on 'Encoding' below for more detail.
|
8
8
|
|
9
|
-
This gem
|
9
|
+
This gem was sponsored by Hetzner (Pty) Ltd - http://hetzner.co.za
|
10
10
|
|
11
11
|
## StorageSQLite
|
12
12
|
|
@@ -113,10 +113,10 @@ If you'd like persistent cache to rather store keys using an encoding of your pr
|
|
113
113
|
|
114
114
|
Please send feedback and comments to the authors at:
|
115
115
|
|
116
|
-
Wynand van Dyk <wynand.van.dyk@hetzner.co.za>
|
117
|
-
|
118
116
|
Ernst van Graan <ernst.van.graan@hetzner.co.za>
|
119
117
|
|
118
|
+
Wynand van Dyk <wynand.van.dyk@hetzner.co.za>
|
119
|
+
|
120
120
|
1. Fork it
|
121
121
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
122
122
|
3. Commit your changes (`git commit -am 'Added some feature'`)
|
data/lib/persistent-cache.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require "persistent-cache/version"
|
2
2
|
require "sqlite3"
|
3
|
-
require "persistent-cache/
|
4
|
-
require "persistent-cache/
|
5
|
-
require "persistent-cache/
|
3
|
+
require "persistent-cache/storage_sqlite"
|
4
|
+
require "persistent-cache/storage_directory"
|
5
|
+
require "persistent-cache/storage_ram"
|
6
6
|
|
7
7
|
module Persistent
|
8
8
|
class Cache
|
@@ -23,7 +23,7 @@ module Persistent
|
|
23
23
|
|
24
24
|
@storage = StorageSQLite.new(storage_details) if storage == STORAGE_SQLITE
|
25
25
|
@storage = StorageDirectory.new(storage_details) if storage == STORAGE_DIRECTORY
|
26
|
-
@storage = StorageRAM.new if storage == STORAGE_RAM
|
26
|
+
@storage = StorageRAM.new(storage_details) if storage == STORAGE_RAM
|
27
27
|
@fresh = fresh
|
28
28
|
@storage_details = storage_details
|
29
29
|
|
data/persistent-cache.gemspec
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'persistent-cache/version'
|
3
5
|
|
4
6
|
Gem::Specification.new do |gem|
|
5
|
-
gem.authors = ["
|
6
|
-
gem.email = ["
|
7
|
+
gem.authors = ["Ernst van Graan", "Wynand van Dyk"]
|
8
|
+
gem.email = ["ernst.van.graan@hetzner.co.za", "wvd@hetzner.co.za"]
|
7
9
|
gem.description = %q{Persistent Cache using a pluggable back-end (e.g. SQLite)}
|
8
10
|
gem.summary = %q{Persistent Cache has a default freshness threshold of 179 days after which entries are no longer returned}
|
9
11
|
gem.homepage = ""
|
@@ -13,11 +15,14 @@ Gem::Specification.new do |gem|
|
|
13
15
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
16
|
gem.name = "persistent-cache"
|
15
17
|
gem.require_paths = ["lib"]
|
16
|
-
gem.version = Persistent::
|
18
|
+
gem.version = Persistent::VERSION
|
17
19
|
gem.add_development_dependency 'rspec', '2.12.0'
|
18
20
|
gem.add_development_dependency 'simplecov'
|
19
21
|
gem.add_development_dependency 'simplecov-rcov'
|
20
|
-
gem.add_development_dependency '
|
21
|
-
gem.add_dependency 'sqlite3', '1.3.10'
|
22
|
+
gem.add_development_dependency 'byebug'
|
22
23
|
gem.add_dependency 'eh'
|
24
|
+
gem.add_dependency "persistent-cache-storage-api"
|
25
|
+
gem.add_dependency "persistent-cache-storage-sqlite"
|
26
|
+
gem.add_dependency "persistent-cache-storage-directory"
|
27
|
+
gem.add_dependency "persistent-cache-storage-ram"
|
23
28
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,7 +3,11 @@ require 'rspec/mocks'
|
|
3
3
|
require 'tempfile'
|
4
4
|
require 'simplecov'
|
5
5
|
require 'simplecov-rcov'
|
6
|
-
require '
|
6
|
+
require 'byebug'
|
7
|
+
require "persistent-cache"
|
8
|
+
require "persistent-cache/storage_sqlite"
|
9
|
+
require "persistent-cache/storage_directory"
|
10
|
+
require "persistent-cache/storage_ram"
|
7
11
|
|
8
12
|
# This file was generated by the `rspec --init` command. Conventionally, all
|
9
13
|
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
metadata
CHANGED
@@ -1,21 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: persistent-cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
|
-
- Wynand van Dyk
|
9
7
|
- Ernst van Graan
|
8
|
+
- Wynand van Dyk
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date:
|
12
|
+
date: 2016-04-12 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: rspec
|
17
16
|
requirement: !ruby/object:Gem::Requirement
|
18
|
-
none: false
|
19
17
|
requirements:
|
20
18
|
- - '='
|
21
19
|
- !ruby/object:Gem::Version
|
@@ -23,7 +21,6 @@ dependencies:
|
|
23
21
|
type: :development
|
24
22
|
prerelease: false
|
25
23
|
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
none: false
|
27
24
|
requirements:
|
28
25
|
- - '='
|
29
26
|
- !ruby/object:Gem::Version
|
@@ -31,102 +28,132 @@ dependencies:
|
|
31
28
|
- !ruby/object:Gem::Dependency
|
32
29
|
name: simplecov
|
33
30
|
requirement: !ruby/object:Gem::Requirement
|
34
|
-
none: false
|
35
31
|
requirements:
|
36
|
-
- -
|
32
|
+
- - ">="
|
37
33
|
- !ruby/object:Gem::Version
|
38
34
|
version: '0'
|
39
35
|
type: :development
|
40
36
|
prerelease: false
|
41
37
|
version_requirements: !ruby/object:Gem::Requirement
|
42
|
-
none: false
|
43
38
|
requirements:
|
44
|
-
- -
|
39
|
+
- - ">="
|
45
40
|
- !ruby/object:Gem::Version
|
46
41
|
version: '0'
|
47
42
|
- !ruby/object:Gem::Dependency
|
48
43
|
name: simplecov-rcov
|
49
44
|
requirement: !ruby/object:Gem::Requirement
|
50
|
-
none: false
|
51
45
|
requirements:
|
52
|
-
- -
|
46
|
+
- - ">="
|
53
47
|
- !ruby/object:Gem::Version
|
54
48
|
version: '0'
|
55
49
|
type: :development
|
56
50
|
prerelease: false
|
57
51
|
version_requirements: !ruby/object:Gem::Requirement
|
58
|
-
none: false
|
59
52
|
requirements:
|
60
|
-
- -
|
53
|
+
- - ">="
|
61
54
|
- !ruby/object:Gem::Version
|
62
55
|
version: '0'
|
63
56
|
- !ruby/object:Gem::Dependency
|
64
|
-
name:
|
57
|
+
name: byebug
|
65
58
|
requirement: !ruby/object:Gem::Requirement
|
66
|
-
none: false
|
67
59
|
requirements:
|
68
|
-
- -
|
60
|
+
- - ">="
|
69
61
|
- !ruby/object:Gem::Version
|
70
62
|
version: '0'
|
71
63
|
type: :development
|
72
64
|
prerelease: false
|
73
65
|
version_requirements: !ruby/object:Gem::Requirement
|
74
|
-
none: false
|
75
66
|
requirements:
|
76
|
-
- -
|
67
|
+
- - ">="
|
77
68
|
- !ruby/object:Gem::Version
|
78
69
|
version: '0'
|
79
70
|
- !ruby/object:Gem::Dependency
|
80
|
-
name:
|
71
|
+
name: eh
|
81
72
|
requirement: !ruby/object:Gem::Requirement
|
82
|
-
none: false
|
83
73
|
requirements:
|
84
|
-
- -
|
74
|
+
- - ">="
|
85
75
|
- !ruby/object:Gem::Version
|
86
|
-
version:
|
76
|
+
version: '0'
|
87
77
|
type: :runtime
|
88
78
|
prerelease: false
|
89
79
|
version_requirements: !ruby/object:Gem::Requirement
|
90
|
-
none: false
|
91
80
|
requirements:
|
92
|
-
- -
|
81
|
+
- - ">="
|
93
82
|
- !ruby/object:Gem::Version
|
94
|
-
version:
|
83
|
+
version: '0'
|
95
84
|
- !ruby/object:Gem::Dependency
|
96
|
-
name:
|
85
|
+
name: persistent-cache-storage-api
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :runtime
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: persistent-cache-storage-sqlite
|
97
100
|
requirement: !ruby/object:Gem::Requirement
|
98
|
-
none: false
|
99
101
|
requirements:
|
100
|
-
- -
|
102
|
+
- - ">="
|
101
103
|
- !ruby/object:Gem::Version
|
102
104
|
version: '0'
|
103
105
|
type: :runtime
|
104
106
|
prerelease: false
|
105
107
|
version_requirements: !ruby/object:Gem::Requirement
|
106
|
-
none: false
|
107
108
|
requirements:
|
108
|
-
- -
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: persistent-cache-storage-directory
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :runtime
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: persistent-cache-storage-ram
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
type: :runtime
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
109
138
|
- !ruby/object:Gem::Version
|
110
139
|
version: '0'
|
111
140
|
description: Persistent Cache using a pluggable back-end (e.g. SQLite)
|
112
141
|
email:
|
113
|
-
- wvd@hetzner.co.za
|
114
142
|
- ernst.van.graan@hetzner.co.za
|
143
|
+
- wvd@hetzner.co.za
|
115
144
|
executables: []
|
116
145
|
extensions: []
|
117
146
|
extra_rdoc_files: []
|
118
147
|
files:
|
119
|
-
- .gitignore
|
120
|
-
- .rspec
|
121
|
-
- .
|
148
|
+
- ".gitignore"
|
149
|
+
- ".rspec"
|
150
|
+
- ".ruby-gemset"
|
151
|
+
- ".ruby-version"
|
122
152
|
- Gemfile
|
123
153
|
- LICENSE
|
124
154
|
- README.md
|
125
155
|
- Rakefile
|
126
156
|
- lib/persistent-cache.rb
|
127
|
-
- lib/persistent-cache/storage/storage_directory.rb
|
128
|
-
- lib/persistent-cache/storage/storage_ram.rb
|
129
|
-
- lib/persistent-cache/storage/storage_sq_lite.rb
|
130
157
|
- lib/persistent-cache/version.rb
|
131
158
|
- persistent-cache.gemspec
|
132
159
|
- spec/persistent-cache_spec.rb
|
@@ -136,27 +163,26 @@ files:
|
|
136
163
|
- spec/storage/storage_sqlite_spec.rb
|
137
164
|
homepage: ''
|
138
165
|
licenses: []
|
166
|
+
metadata: {}
|
139
167
|
post_install_message:
|
140
168
|
rdoc_options: []
|
141
169
|
require_paths:
|
142
170
|
- lib
|
143
171
|
required_ruby_version: !ruby/object:Gem::Requirement
|
144
|
-
none: false
|
145
172
|
requirements:
|
146
|
-
- -
|
173
|
+
- - ">="
|
147
174
|
- !ruby/object:Gem::Version
|
148
175
|
version: '0'
|
149
176
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
|
-
none: false
|
151
177
|
requirements:
|
152
|
-
- -
|
178
|
+
- - ">="
|
153
179
|
- !ruby/object:Gem::Version
|
154
180
|
version: '0'
|
155
181
|
requirements: []
|
156
182
|
rubyforge_project:
|
157
|
-
rubygems_version:
|
183
|
+
rubygems_version: 2.5.1
|
158
184
|
signing_key:
|
159
|
-
specification_version:
|
185
|
+
specification_version: 4
|
160
186
|
summary: Persistent Cache has a default freshness threshold of 179 days after which
|
161
187
|
entries are no longer returned
|
162
188
|
test_files:
|
data/.rvmrc
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
#!/usr/bin/env bash
|
2
|
-
|
3
|
-
# This is an RVM Project .rvmrc file, used to automatically load the ruby
|
4
|
-
# development environment upon cd'ing into the directory
|
5
|
-
|
6
|
-
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,
|
7
|
-
# Only full ruby name is supported here, for short names use:
|
8
|
-
# echo "rvm use 1.9.3" > .rvmrc
|
9
|
-
environment_id="ruby-1.9.3-p194@persistent-hash"
|
10
|
-
|
11
|
-
# Uncomment the following lines if you want to verify rvm version per project
|
12
|
-
# rvmrc_rvm_version="1.14.3 (stable)" # 1.10.1 seams as a safe start
|
13
|
-
# eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
|
14
|
-
# echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
|
15
|
-
# return 1
|
16
|
-
# }
|
17
|
-
|
18
|
-
# First we attempt to load the desired environment directly from the environment
|
19
|
-
# file. This is very fast and efficient compared to running through the entire
|
20
|
-
# CLI and selector. If you want feedback on which environment was used then
|
21
|
-
# insert the word 'use' after --create as this triggers verbose mode.
|
22
|
-
if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
|
23
|
-
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
|
24
|
-
then
|
25
|
-
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
|
26
|
-
[[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] &&
|
27
|
-
\. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true
|
28
|
-
else
|
29
|
-
# If the environment file has not yet been created, use the RVM CLI to select.
|
30
|
-
rvm --create "$environment_id" || {
|
31
|
-
echo "Failed to create RVM environment '${environment_id}'."
|
32
|
-
return 1
|
33
|
-
}
|
34
|
-
fi
|
35
|
-
|
36
|
-
# If you use bundler, this might be useful to you:
|
37
|
-
# if [[ -s Gemfile ]] && {
|
38
|
-
# ! builtin command -v bundle >/dev/null ||
|
39
|
-
# builtin command -v bundle | GREP_OPTIONS= \grep $rvm_path/bin/bundle >/dev/null
|
40
|
-
# }
|
41
|
-
# then
|
42
|
-
# printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n"
|
43
|
-
# gem install bundler
|
44
|
-
# fi
|
45
|
-
# if [[ -s Gemfile ]] && builtin command -v bundle >/dev/null
|
46
|
-
# then
|
47
|
-
# bundle install | GREP_OPTIONS= \grep -vE '^Using|Your bundle is complete'
|
48
|
-
# fi
|
@@ -1,170 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
require 'tempfile'
|
3
|
-
require 'pathname'
|
4
|
-
|
5
|
-
module Persistent
|
6
|
-
class StorageDirectory
|
7
|
-
CACHE_FILE = "cache.gz" unless defined? CACHE_FILE; CACHE_FILE.freeze
|
8
|
-
|
9
|
-
attr_accessor :storage_root
|
10
|
-
|
11
|
-
def initialize(storage_details)
|
12
|
-
raise ArgumentError.new("Storage details not provided") if storage_details.nil? or storage_details == ""
|
13
|
-
@storage_root = storage_details
|
14
|
-
connect_to_database
|
15
|
-
end
|
16
|
-
|
17
|
-
def connect_to_database
|
18
|
-
FileUtils.makedirs([@storage_root]) if not File.directory?(@storage_root)
|
19
|
-
end
|
20
|
-
|
21
|
-
def save_key_value_pair(key, value, timestamp = nil)
|
22
|
-
prepare_to_store_key_value(key, value, timestamp)
|
23
|
-
store_key_value(key, value, get_time(timestamp)) if not value.nil?
|
24
|
-
end
|
25
|
-
|
26
|
-
def lookup_key(key)
|
27
|
-
validate_key(key)
|
28
|
-
return [] if not File.exists? compile_value_path(key)
|
29
|
-
lookup_key_value_timestamp(key)
|
30
|
-
end
|
31
|
-
|
32
|
-
def delete_entry(key)
|
33
|
-
validate_key(key)
|
34
|
-
FileUtils.rm_rf(compile_key_path(key))
|
35
|
-
end
|
36
|
-
|
37
|
-
def size
|
38
|
-
count = Dir::glob("#{@storage_root}/**/#{CACHE_FILE}").size
|
39
|
-
end
|
40
|
-
|
41
|
-
def keys
|
42
|
-
return [] if size == 0
|
43
|
-
list_keys_sorted
|
44
|
-
end
|
45
|
-
|
46
|
-
def clear
|
47
|
-
keys.each do |key|
|
48
|
-
delete_entry(key[0])
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def get_value_path(key)
|
53
|
-
validate_key(key)
|
54
|
-
|
55
|
-
return nil if not key_cached?(key)
|
56
|
-
|
57
|
-
compile_value_path(key)
|
58
|
-
end
|
59
|
-
|
60
|
-
def get_value_path_even_when_not_cached(key)
|
61
|
-
compile_value_path(key)
|
62
|
-
end
|
63
|
-
|
64
|
-
def key_cached?(key)
|
65
|
-
# don't read the value here, as it may be very large - rather look whether the key is present
|
66
|
-
File.exists? compile_key_path(key)
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def list_keys_sorted
|
72
|
-
result = []
|
73
|
-
append_keys(result).sort
|
74
|
-
end
|
75
|
-
|
76
|
-
def append_keys(result)
|
77
|
-
get_key_directories.each do |dir|
|
78
|
-
result << extract_key_from_directory(dir)
|
79
|
-
end
|
80
|
-
result
|
81
|
-
end
|
82
|
-
|
83
|
-
def get_key_directories
|
84
|
-
subdirectories = Dir::glob("#{@storage_root}/**/")
|
85
|
-
#exclude the storage root directory itself
|
86
|
-
subdirectories[1..-1]
|
87
|
-
end
|
88
|
-
|
89
|
-
def extract_key_from_directory(dir)
|
90
|
-
key = dir.match(/#{@storage_root}\/(\w+)\//)[1]
|
91
|
-
[key]
|
92
|
-
end
|
93
|
-
|
94
|
-
def compile_key_path(key)
|
95
|
-
"#{@storage_root}/#{key}"
|
96
|
-
end
|
97
|
-
|
98
|
-
def compile_value_path(key)
|
99
|
-
"#{compile_key_path(key)}/#{CACHE_FILE}"
|
100
|
-
end
|
101
|
-
|
102
|
-
def validate_save_key_value_pair(key, value)
|
103
|
-
validate_key(key)
|
104
|
-
raise ArgumentError.new("Only string values allowed") if not value.is_a?(String)
|
105
|
-
end
|
106
|
-
|
107
|
-
def lookup_key_value_timestamp(key)
|
108
|
-
result = [[],[]]
|
109
|
-
data = File.read(compile_value_path(key))
|
110
|
-
format_value_timestamp(result, data)
|
111
|
-
end
|
112
|
-
|
113
|
-
def format_value_timestamp(result, data)
|
114
|
-
result[0][0] = data.lines.to_a[1..-1].join
|
115
|
-
result[0][1] = data.lines.to_a[0..0].join.split("\n")[0]
|
116
|
-
result
|
117
|
-
end
|
118
|
-
|
119
|
-
def validate_key(key)
|
120
|
-
raise ArgumentError.new("Only string keys allowed") if not key.is_a?(String)
|
121
|
-
root_path = Pathname.new(File.absolute_path(@storage_root))
|
122
|
-
key_path = Pathname.new(File.absolute_path(compile_key_path(key)))
|
123
|
-
relative = key_path.relative_path_from(root_path).to_s
|
124
|
-
raise ArgumentError.new("key is outside of storage_root scope") if relative.start_with?("..")
|
125
|
-
raise ArgumentError.new("key is the same as storage_root") if relative == "."
|
126
|
-
end
|
127
|
-
|
128
|
-
def empty_key_value(key)
|
129
|
-
FileUtils.makedirs([compile_key_path(key)]) if not File.exists?(compile_key_path(key))
|
130
|
-
FileUtils.rm_f(compile_value_path(key))
|
131
|
-
end
|
132
|
-
|
133
|
-
def get_time(timestamp)
|
134
|
-
timestamp.nil? ? Time.now.to_s : timestamp.to_s
|
135
|
-
end
|
136
|
-
|
137
|
-
def prepare_to_store_key_value(key, value, timestamp)
|
138
|
-
validate_save_key_value_pair(key, value)
|
139
|
-
delete_entry(key)
|
140
|
-
empty_key_value(key)
|
141
|
-
end
|
142
|
-
|
143
|
-
def store_key_value(key, value, timestamp)
|
144
|
-
tempfile = Tempfile.new("store_key_value")
|
145
|
-
store_value_timestamp_in_file(value, timestamp, tempfile)
|
146
|
-
sync_cache_value(key, tempfile)
|
147
|
-
end
|
148
|
-
|
149
|
-
def sync_cache_value(key, tempfile)
|
150
|
-
target = compile_value_path(key)
|
151
|
-
FileUtils.rm_f(target)
|
152
|
-
FileUtils.move(tempfile.path, target)
|
153
|
-
end
|
154
|
-
|
155
|
-
def store_value_timestamp_in_file(value, timestamp, tempfile)
|
156
|
-
output = File.open(tempfile, 'a')
|
157
|
-
write_value_timestamp(output, value, timestamp)
|
158
|
-
output.close
|
159
|
-
end
|
160
|
-
|
161
|
-
def write_value_timestamp(output, value, timestamp)
|
162
|
-
# Have to be explicit about writing to the file. 'puts' collapses newline at the end of the file and
|
163
|
-
# so does not guarantee exact replication of 'value' on lookup
|
164
|
-
output.write(timestamp)
|
165
|
-
output.write("\n")
|
166
|
-
output.write(value)
|
167
|
-
output.flush
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
require "eh/eh"
|
2
|
-
|
3
|
-
module Persistent
|
4
|
-
class StorageRAM
|
5
|
-
attr_accessor :storage
|
6
|
-
|
7
|
-
def initialize()
|
8
|
-
@storage = {}
|
9
|
-
end
|
10
|
-
|
11
|
-
def save_key_value_pair(serialized_key, serialized_value, timestamp = nil)
|
12
|
-
delete_entry(serialized_key)
|
13
|
-
time_entry = timestamp.nil? ? Time.now.to_s : timestamp.to_s
|
14
|
-
EH::retry!(:args => [serialized_key, serialized_value, time_entry]) do
|
15
|
-
@storage[serialized_key] = {:value => serialized_value, :timestamp => time_entry}
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def lookup_key(serialized_key)
|
20
|
-
EH::retry!(:args => [serialized_key]) do
|
21
|
-
return [] if @storage[serialized_key].nil?
|
22
|
-
[@storage[serialized_key][:value], @storage[serialized_key][:timestamp]]
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def delete_entry(serialized_key)
|
27
|
-
EH::retry!(:args => [serialized_key]) do
|
28
|
-
@storage.delete(serialized_key)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def size
|
33
|
-
EH::retry!(:args => []) do
|
34
|
-
@storage.size
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def keys
|
39
|
-
EH::retry!(:args => []) do
|
40
|
-
return [] if @storage.keys == []
|
41
|
-
[@storage.keys]
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def clear
|
46
|
-
EH::retry!(:args => []) do
|
47
|
-
@storage.clear
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,97 +0,0 @@
|
|
1
|
-
require "sqlite3"
|
2
|
-
require "base64"
|
3
|
-
require "eh/eh"
|
4
|
-
|
5
|
-
module Persistent
|
6
|
-
class StorageSQLite
|
7
|
-
DB_TABLE = "key_value" unless defined? DB_TABLE; DB_TABLE.freeze
|
8
|
-
DB_TIMEOUT = 30000 unless defined? DB_TIMEOUT; DB_TIMEOUT.freeze
|
9
|
-
|
10
|
-
attr_accessor :storage_details
|
11
|
-
attr_accessor :storage_handler
|
12
|
-
|
13
|
-
def initialize(storage_details)
|
14
|
-
raise ArgumentError.new("Storage details not provided") if storage_details.nil? or storage_details == ""
|
15
|
-
@storage_details = storage_details
|
16
|
-
@storage_handler = connect_to_database
|
17
|
-
@storage_handler.busy_timeout = 30000
|
18
|
-
end
|
19
|
-
|
20
|
-
def save_key_value_pair(key, value, timestamp = nil)
|
21
|
-
delete_entry(key)
|
22
|
-
time_entry = timestamp.nil? ? Time.now.to_s : timestamp.to_s
|
23
|
-
EH::retry!(:args => [serialize(key), serialize(value), time_entry]) do
|
24
|
-
@storage_handler.execute("INSERT INTO #{DB_TABLE} (key, value, timestamp) VALUES(?, ?, ?)",serialize(key), serialize(value), time_entry)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def lookup_key(key)
|
29
|
-
EH::retry!(:args => [serialize(key)]) do
|
30
|
-
result = @storage_handler.execute("SELECT value, timestamp FROM #{DB_TABLE} WHERE key=?", serialize(key))
|
31
|
-
!result.nil? && !result.empty? ? [deserialize(result[0][0]), result[0][1]] : nil
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def delete_entry(key)
|
36
|
-
EH::retry!(:args => [serialize(key)]) do
|
37
|
-
@storage_handler.execute("DELETE FROM #{DB_TABLE} WHERE key=?", serialize(key))
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def size
|
42
|
-
EH::retry!(:args => []) do
|
43
|
-
@storage_handler.execute("SELECT value FROM #{DB_TABLE}").size
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def keys
|
48
|
-
EH::retry!(:args => []) do
|
49
|
-
@storage_handler.execute("SELECT key FROM #{DB_TABLE}").collect { |k| deserialize(k[0]) }
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def clear
|
54
|
-
EH::retry!(:args => []) do
|
55
|
-
@storage_handler.execute("DELETE FROM #{DB_TABLE}")
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
def serialize(data)
|
62
|
-
Base64.encode64(Marshal.dump(data))
|
63
|
-
end
|
64
|
-
|
65
|
-
def deserialize(data)
|
66
|
-
Marshal.load(Base64.decode64(data))
|
67
|
-
|
68
|
-
rescue TypeError => ex
|
69
|
-
Marshal.load(data)
|
70
|
-
end
|
71
|
-
|
72
|
-
def connect_to_database
|
73
|
-
File.exists?(@storage_details) ? open_database : create_database
|
74
|
-
end
|
75
|
-
|
76
|
-
def open_database
|
77
|
-
EH::retry!(:args => []) do
|
78
|
-
SQLite3::Database.open(@storage_details)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def create_database
|
83
|
-
EH::retry!(:args => []) do
|
84
|
-
@storage_handler = SQLite3::Database.new(@storage_details)
|
85
|
-
create_table
|
86
|
-
end
|
87
|
-
@storage_handler
|
88
|
-
end
|
89
|
-
|
90
|
-
def create_table
|
91
|
-
EH::retry!(:args => []) do
|
92
|
-
@storage_handler.execute("CREATE TABLE #{DB_TABLE}(key TEXT PRIMARY KEY, value TEXT, timestamp TEXT)")
|
93
|
-
end
|
94
|
-
@storage_handler
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|