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 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