persistent-cache 0.1.2 → 0.1.3
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/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Persistent::Cache
|
2
2
|
|
3
|
-
Persistent cache behaves like a hash, with a pluggable back-end. Currently sqlite3
|
3
|
+
Persistent cache behaves like a hash, with a pluggable back-end. Currently sqlite3, file system directory and RAM back-ends are provided. The cache defaults to type STORAGE_SQLITE
|
4
4
|
|
5
5
|
Values in the cache have a default freshness period of 15465600 ms. This can be configured in the cache initializer. Setting fresh = nil indicates that data remains fresh for-ever. Each user of the cache may have his own independent freshness value. If stale data is requested from the cache, nil is returned. Data is marshalled before storage. If a key is not found in the cache, nil is returned. Setting the value of a key in the cache to nil deletes the entry. If required, creation time of an entry can be specified using set(key, value, timestamp)
|
6
6
|
|
@@ -20,6 +20,10 @@ When a StorageDirectory is used, it can be asked whether a key is present and wh
|
|
20
20
|
|
21
21
|
key_cached?(key)
|
22
22
|
|
23
|
+
## StorageRAM
|
24
|
+
|
25
|
+
Updates to the cache are stored in RAM using a hash.
|
26
|
+
|
23
27
|
## Installation
|
24
28
|
|
25
29
|
Add this line to your application's Gemfile:
|
@@ -74,10 +78,12 @@ Or install it yourself as:
|
|
74
78
|
|
75
79
|
cache = Persistent::Cache.new("/tmp/my-persistent-cache", nil) # for-ever fresh
|
76
80
|
|
77
|
-
cache = Persistent::Cache.new("/tmp/directory-cache", nil, STORAGE_DIRECTORY)
|
81
|
+
cache = Persistent::Cache.new("/tmp/directory-cache", nil, Persistent::Cache::STORAGE_DIRECTORY)
|
78
82
|
|
79
83
|
cache.set("mykey", "myvalue", Time.now) # explicitly set creation time
|
80
84
|
|
85
|
+
cache = Persistent::Cache.new("cache-name", nil, Persistent::Cache::STORAGE_RAM)
|
86
|
+
|
81
87
|
Please send feedback and comments to the authors at:
|
82
88
|
|
83
89
|
Wynand van Dyk <wynand.van.dyk@hetzner.co.za>
|
data/lib/persistent-cache.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
require "persistent-cache/version"
|
2
2
|
require "sqlite3"
|
3
3
|
require "persistent-cache/storage/storage_sq_lite"
|
4
|
+
require "persistent-cache/storage/storage_directory"
|
5
|
+
require "persistent-cache/storage/storage_ram"
|
4
6
|
|
5
7
|
module Persistent
|
6
8
|
class Cache
|
7
9
|
STORAGE_SQLITE = 'sqlite' unless defined? STORAGE_SQLITE
|
8
10
|
STORAGE_DIRECTORY = 'directory' unless defined? STORAGE_DIRECTORY
|
11
|
+
STORAGE_RAM = 'ram' unless defined? STORAGE_RAM
|
9
12
|
|
10
13
|
# Fresh is 1 day less than the bacula default job retention time. If this is configured differently, FRESH should be updated as well.
|
11
14
|
FRESH = 15465600; FRESH.freeze
|
@@ -19,6 +22,7 @@ module Persistent
|
|
19
22
|
|
20
23
|
@storage = StorageSQLite.new(storage_details) if storage == STORAGE_SQLITE
|
21
24
|
@storage = StorageDirectory.new(storage_details) if storage == STORAGE_DIRECTORY
|
25
|
+
@storage = StorageRAM.new if storage == STORAGE_RAM
|
22
26
|
@fresh = fresh
|
23
27
|
@storage_details = storage_details
|
24
28
|
|
@@ -0,0 +1,54 @@
|
|
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
|
+
result = [[]]
|
23
|
+
result[0][0] = @storage[serialized_key][:value]
|
24
|
+
result[0][1] = @storage[serialized_key][:timestamp]
|
25
|
+
result
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete_entry(serialized_key)
|
30
|
+
EH::retry!(:args => [serialized_key]) do
|
31
|
+
@storage.delete(serialized_key)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def size
|
36
|
+
EH::retry!(:args => []) do
|
37
|
+
@storage.size
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def keys
|
42
|
+
EH::retry!(:args => []) do
|
43
|
+
return [] if @storage.keys == []
|
44
|
+
[@storage.keys]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def clear
|
49
|
+
EH::retry!(:args => []) do
|
50
|
+
@storage.clear
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require "persistent-cache/storage/storage_ram"
|
3
|
+
|
4
|
+
describe Persistent::StorageRAM do
|
5
|
+
before :each do
|
6
|
+
@test_key = "testkey"
|
7
|
+
@test_value = "testvalue"
|
8
|
+
@iut = Persistent::StorageRAM.new
|
9
|
+
end
|
10
|
+
|
11
|
+
context "when constructed" do
|
12
|
+
it "should have a storage hash in RAM" do
|
13
|
+
@iut.storage.nil?.should == false
|
14
|
+
@iut.storage.instance_of?(Hash).should == true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when asked to store a key value pair" do
|
19
|
+
it "should store the key/value pair in RAM, with the current time as timestamp" do
|
20
|
+
start_time = Time.now - 1
|
21
|
+
@iut.save_key_value_pair(Marshal.dump(@test_key), Marshal.dump(@test_value))
|
22
|
+
result = @iut.lookup_key(Marshal.dump(@test_key))
|
23
|
+
result.nil?.should == false
|
24
|
+
result[0].nil?.should == false
|
25
|
+
result[0][0].should == Marshal.dump(@test_value)
|
26
|
+
test_time = Time.parse(result[0][1])
|
27
|
+
test_time.should > start_time and test_time.should < start_time + 600
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should store the key/value pair in RAM, with a timestamp specified" do
|
31
|
+
test_time = (Time.now - 2500)
|
32
|
+
@iut.save_key_value_pair(Marshal.dump(@test_key), Marshal.dump(@test_value), test_time)
|
33
|
+
result = @iut.lookup_key(Marshal.dump(@test_key))
|
34
|
+
result.nil?.should == false
|
35
|
+
result[0].nil?.should == false
|
36
|
+
result[0][0].should == Marshal.dump(@test_value)
|
37
|
+
time_retrieved = Time.parse(result[0][1])
|
38
|
+
time_retrieved.to_s.should == test_time.to_s
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should overwrite the existing key/value pair if they already exist" do
|
42
|
+
@iut.save_key_value_pair(Marshal.dump(@test_key), Marshal.dump(@test_value))
|
43
|
+
@iut.save_key_value_pair(Marshal.dump(@test_key), Marshal.dump("testvalue2"))
|
44
|
+
result = @iut.lookup_key(Marshal.dump(@test_key))
|
45
|
+
result.nil?.should == false
|
46
|
+
result[0].nil?.should == false
|
47
|
+
result.size.should == 1
|
48
|
+
result[0][0].should == Marshal.dump("testvalue2")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "When looking up a value given its key" do
|
53
|
+
it "should retrieve the value from RAM" do
|
54
|
+
@iut.save_key_value_pair(Marshal.dump(@test_key), Marshal.dump(@test_value))
|
55
|
+
result = @iut.lookup_key(Marshal.dump(@test_key))
|
56
|
+
result[0][0].should == Marshal.dump(@test_value)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should retrieve the timestamp when the value was stored from RAM" do
|
60
|
+
now = Time.now.to_s
|
61
|
+
@iut.save_key_value_pair(Marshal.dump(@test_key), Marshal.dump(@test_value))
|
62
|
+
sleep 1
|
63
|
+
result = @iut.lookup_key(Marshal.dump(@test_key))
|
64
|
+
result[0][1].should == now
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should return an empty array if a key is not in RAM" do
|
68
|
+
@iut.delete_entry(Marshal.dump(@test_key))
|
69
|
+
result = @iut.lookup_key(Marshal.dump(@test_key))
|
70
|
+
result.should == []
|
71
|
+
result[0].should == nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "when asked to delete an entry" do
|
76
|
+
it "should not raise an error if the entry is not present" do
|
77
|
+
@iut.delete_entry(Marshal.dump("shouldnotbepresent"))
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should delete the entry if it is present" do
|
81
|
+
@iut.save_key_value_pair(Marshal.dump(@test_key), Marshal.dump(@test_value))
|
82
|
+
result = @iut.lookup_key(Marshal.dump(@test_key))
|
83
|
+
result[0][0].should == Marshal.dump(@test_value)
|
84
|
+
@iut.delete_entry(Marshal.dump(@test_key))
|
85
|
+
result = @iut.lookup_key(Marshal.dump(@test_key))
|
86
|
+
result.should == []
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when asked the size of the RAM database" do
|
91
|
+
it "should return 0 if the RAM database has no entries" do
|
92
|
+
@iut.size.should == 0
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should return the number of entries" do
|
96
|
+
populate_database(@iut)
|
97
|
+
@iut.size.should == 3
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "when asked for the keys in the RAM database" do
|
102
|
+
it "should return an empty array if there are no entries in the RAM database" do
|
103
|
+
@iut.keys.should == []
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should return the keys in the RAM database" do
|
107
|
+
populate_database(@iut)
|
108
|
+
keys = @iut.keys.flatten
|
109
|
+
keys.include?(Marshal.dump("one")).should == true
|
110
|
+
keys.include?(Marshal.dump("two")).should == true
|
111
|
+
keys.include?(Marshal.dump("three")).should == true
|
112
|
+
@iut.size.should == 3
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should return the keys in an array, with each key in its own sub-array" do
|
116
|
+
populate_database(@iut)
|
117
|
+
found = false
|
118
|
+
test = Marshal.dump("one")
|
119
|
+
found = true if (@iut.keys[0][0] == test or @iut.keys[0][1] == test or @iut.keys[0][2] == test)
|
120
|
+
found.should == true
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "when asked to clear the RAM database" do
|
125
|
+
it "should delete all entries in RAM" do
|
126
|
+
populate_database(@iut)
|
127
|
+
@iut.clear
|
128
|
+
@iut.size.should == 0
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def populate_database(iut)
|
133
|
+
iut.save_key_value_pair(Marshal.dump("one"), Marshal.dump("one"))
|
134
|
+
iut.save_key_value_pair(Marshal.dump("two"), Marshal.dump("two"))
|
135
|
+
iut.save_key_value_pair(Marshal.dump("three"), Marshal.dump("three"))
|
136
|
+
end
|
137
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: persistent-cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-
|
13
|
+
date: 2013-08-16 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -109,6 +109,7 @@ files:
|
|
109
109
|
- Rakefile
|
110
110
|
- lib/persistent-cache.rb
|
111
111
|
- lib/persistent-cache/storage/storage_directory.rb
|
112
|
+
- lib/persistent-cache/storage/storage_ram.rb
|
112
113
|
- lib/persistent-cache/storage/storage_sq_lite.rb
|
113
114
|
- lib/persistent-cache/version.rb
|
114
115
|
- multidb
|
@@ -116,6 +117,7 @@ files:
|
|
116
117
|
- spec/persistent-cache_spec.rb
|
117
118
|
- spec/spec_helper.rb
|
118
119
|
- spec/storage/storage_directory_spec.rb
|
120
|
+
- spec/storage/storage_ram_spec.rb
|
119
121
|
- spec/storage/storage_sqlite_spec.rb
|
120
122
|
homepage: ''
|
121
123
|
licenses: []
|
@@ -137,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
137
139
|
version: '0'
|
138
140
|
requirements: []
|
139
141
|
rubyforge_project:
|
140
|
-
rubygems_version: 1.8.
|
142
|
+
rubygems_version: 1.8.25
|
141
143
|
signing_key:
|
142
144
|
specification_version: 3
|
143
145
|
summary: Persistent Cache has a default freshness threshold of 179 days after which
|
@@ -146,4 +148,5 @@ test_files:
|
|
146
148
|
- spec/persistent-cache_spec.rb
|
147
149
|
- spec/spec_helper.rb
|
148
150
|
- spec/storage/storage_directory_spec.rb
|
151
|
+
- spec/storage/storage_ram_spec.rb
|
149
152
|
- spec/storage/storage_sqlite_spec.rb
|