persistent-cache 0.4.1 → 1.0.0
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/.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
|