persistent-cache 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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 and file system directory back-ends are provided. The cache defaults to type STORAGE_SQLITE
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>
@@ -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
 
@@ -1,4 +1,5 @@
1
1
  require 'fileutils'
2
+ require 'tempfile'
2
3
 
3
4
  module Persistent
4
5
  class StorageDirectory
@@ -162,4 +163,4 @@ module Persistent
162
163
  end
163
164
 
164
165
  end
165
- end
166
+ end
@@ -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
@@ -1,5 +1,5 @@
1
1
  module Persistent
2
2
  class Cache
3
- VERSION = "0.1.2"
3
+ VERSION = "0.1.3"
4
4
  end
5
5
  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.2
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-06-12 00:00:00.000000000 Z
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.24
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