large_object_store 0.0.1

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/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ rvm:
2
+ - ree
3
+ - 1.9.2
4
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+ gemspec
3
+
4
+ gem "bump"
5
+ gem "rake"
6
+ gem "rspec", "~>2"
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ large_object_store (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ bump (0.3.9)
10
+ diff-lcs (1.1.3)
11
+ rake (10.0.3)
12
+ rspec (2.12.0)
13
+ rspec-core (~> 2.12.0)
14
+ rspec-expectations (~> 2.12.0)
15
+ rspec-mocks (~> 2.12.0)
16
+ rspec-core (2.12.2)
17
+ rspec-expectations (2.12.1)
18
+ diff-lcs (~> 1.1.3)
19
+ rspec-mocks (2.12.2)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ bump
26
+ large_object_store!
27
+ rake
28
+ rspec (~> 2)
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "bump/tasks"
3
+
4
+ task :default do
5
+ sh "rspec spec/"
6
+ end
data/Readme.md ADDED
@@ -0,0 +1,32 @@
1
+ Store large objects in memcache or others by slicing them.
2
+ - uses read_multi for fast access
3
+ - returns nil if one slice is missing
4
+
5
+ Install
6
+ =======
7
+
8
+ ```Bash
9
+ gem install large_object_store
10
+ ```
11
+
12
+ Usage
13
+ =====
14
+
15
+ ```Ruby
16
+ Rails.cache.write("a", "a"*10_000_000) # => false -> oops too large
17
+
18
+ store = LargeObjectStore.wrap(Rails.cache)
19
+ store.write("a", "a"*10_000_000) # => true -> always!
20
+ store.read("a").size # => 10_000_000 using multi_get
21
+ store.read("b") # => nil
22
+ store.fetch("a"){ "something" } # => "something" executes block on miss
23
+ ```
24
+
25
+ Author
26
+ ======
27
+ [Ana Martinez](https://github.com/anamartinez)<br/>
28
+ acemacu@gmail.com<br/>
29
+ [Michael Grosser](https://github.com/grosser)<br/>
30
+ michael@grosser.it<br/>
31
+ License: MIT<br/>
32
+ [![Build Status](https://travis-ci.org/anamartinez/large_object_store.png)](https://travis-ci.org/anamartinez/large_object_store)
@@ -0,0 +1,20 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDMjCCAhqgAwIBAgIBADANBgkqhkiG9w0BAQUFADA/MRAwDgYDVQQDDAdtaWNo
3
+ YWVsMRcwFQYKCZImiZPyLGQBGRYHZ3Jvc3NlcjESMBAGCgmSJomT8ixkARkWAml0
4
+ MB4XDTEzMDIwMzE4MTMxMVoXDTE0MDIwMzE4MTMxMVowPzEQMA4GA1UEAwwHbWlj
5
+ aGFlbDEXMBUGCgmSJomT8ixkARkWB2dyb3NzZXIxEjAQBgoJkiaJk/IsZAEZFgJp
6
+ dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMorXo/hgbUq97+kII9H
7
+ MsQcLdC/7wQ1ZP2OshVHPkeP0qH8MBHGg6eYisOX2ubNagF9YTCZWnhrdKrwpLOO
8
+ cPLaZbjUjljJ3cQR3B8Yn1veV5IhG86QseTBjymzJWsLpqJ1UZGpfB9tXcsFtuxO
9
+ 6vHvcIHdzvc/OUkICttLbH+1qb6rsHUceqh+JrH4GrsJ5H4hAfIdyS2XMK7YRKbh
10
+ h+IBu6dFWJJByzFsYmV1PDXln3UBmgAt65cmCu4qPfThioCGDzbSJrGDGLmw/pFX
11
+ FPpVCm1zgYSb1v6Qnf3cgXa2f2wYGm17+zAVyIDpwryFru9yF/jJxE38z/DRsd9R
12
+ /88CAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUsiNnXHtKeMYYcr4yJVmQ
13
+ WONL+IwwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQAlyN7kKo/NQCQ0
14
+ AOzZLZ3WAePvStkCFIJ53tsv5Kyo4pMAllv+BgPzzBt7qi605mFSL6zBd9uLou+W
15
+ Co3s48p1dy7CjjAfVQdmVNHF3MwXtfC2OEyvSQPi4xKR8iba8wa3xp9LVo1PuLpw
16
+ /6DsrChWw74HfsJN6qJOK684hJeT8lBYAUfiC3wD0owoPSg+XtyAAddisR+KV5Y1
17
+ NmVHuLtQcNTZy+gRht3ahJRMuC6QyLmkTsf+6MaenwAMkAgHdswGsJztOnNnBa3F
18
+ y0kCSWmK6D+x/SbfS6r7Ke07MRqziJdB9GuE1+0cIRuFh8EQ+LN6HXCKM5pon/GU
19
+ ycwMXfl0
20
+ -----END CERTIFICATE-----
@@ -0,0 +1,17 @@
1
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
2
+ name = "large_object_store"
3
+ require "#{name.gsub("-","/")}/version"
4
+
5
+ Gem::Specification.new name, LargeObjectStore::VERSION do |s|
6
+ s.summary = "Store large objects in memcache or others"
7
+ s.authors = ["Ana Martinez"]
8
+ s.email = "acemacu@gmail.com"
9
+ s.homepage = "http://github.com/anamartinez/#{name}"
10
+ s.files = `git ls-files`.split("\n")
11
+ s.license = "MIT"
12
+ cert = File.expand_path("~/.ssh/gem-private_key.pem")
13
+ if File.exist?(cert)
14
+ s.signing_key = cert
15
+ s.cert_chain = ["gem-public_cert.pem"]
16
+ end
17
+ end
@@ -0,0 +1,58 @@
1
+ require "large_object_store/version"
2
+
3
+ module LargeObjectStore
4
+
5
+ def self.wrap(store)
6
+ RailsWrapper.new(store)
7
+ end
8
+
9
+ class RailsWrapper
10
+ attr_reader :store
11
+
12
+ LIMIT = 1024**2 - 100
13
+
14
+ def initialize(store)
15
+ @store = store
16
+ end
17
+
18
+ def write(key, value, options = {})
19
+ value = Marshal.dump(value)
20
+
21
+ # store number of pages
22
+ pages = (value.size / LIMIT.to_f).ceil
23
+ @store.write("#{key}_0", pages, options)
24
+
25
+ # store object
26
+ page = 1
27
+ loop do
28
+ slice = value.slice!(0, LIMIT)
29
+ break if slice.size == 0
30
+
31
+ @store.write("#{key}_#{page}", slice, options)
32
+ page += 1
33
+ end
34
+
35
+ true
36
+ end
37
+
38
+ def read(key)
39
+ # read pages
40
+ pages = @store.read("#{key}_0")
41
+ return if pages.nil?
42
+
43
+ # read sliced data
44
+ keys = Array.new(pages).each_with_index.map{|_,i| "#{key}_#{i+1}" }
45
+ slices = @store.read_multi(*keys).values
46
+ return nil if slices.compact.size < pages
47
+ Marshal.load(slices.join(""))
48
+ end
49
+
50
+ def fetch(key, options={})
51
+ value = read(key)
52
+ return value unless value.nil?
53
+ value = yield
54
+ write(key, value, options)
55
+ value
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module LargeObjectStore
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,107 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ class TestCache
5
+ def initialize
6
+ @data = {}
7
+ end
8
+
9
+ def write(k,v, options={})
10
+ v = Marshal.dump(v)
11
+ return false if v.bytesize > 1024**2
12
+ @data[k] = v
13
+ true
14
+ end
15
+
16
+ def read(k)
17
+ real_read(k)
18
+ end
19
+
20
+ def real_read(k)
21
+ v = @data[k]
22
+ v.nil? ? nil : Marshal.load(v)
23
+ end
24
+
25
+ def read_multi(*keys)
26
+ Hash[keys.map{|k| [k, real_read(k)] }]
27
+ end
28
+
29
+ def keys
30
+ @data.keys
31
+ end
32
+ end
33
+
34
+ describe LargeObjectStore do
35
+ let(:store) { LargeObjectStore.wrap(TestCache.new) }
36
+
37
+ it "has a VERSION" do
38
+ LargeObjectStore::VERSION.should =~ /^[\.\da-z]+$/
39
+ end
40
+
41
+ it "wraps and returns a wrapper" do
42
+ store.class.should == LargeObjectStore::RailsWrapper
43
+ end
44
+
45
+ it "can write/read big objects" do
46
+ store.write("a", "a"*10_000_000).should == true
47
+ store.read("a").size.should == 10_000_000
48
+ end
49
+
50
+ it "passes options" do
51
+ store.store.should_receive(:write).with(anything, anything, :expires_in => 111).twice
52
+ store.write("a", "a", :expires_in => 111)
53
+ end
54
+
55
+ it "cannot read corrupted objects" do
56
+ store.write("a", ["a"*10_000_000]).should == true
57
+ store.store.write("a_4", nil)
58
+ store.read("a").should == nil
59
+ end
60
+
61
+ it "can write/read big non-string objects" do
62
+ store.write("a", ["a"*10_000_000]).should == true
63
+ store.read("a").first.size.should == 10_000_000
64
+ end
65
+
66
+ it "can read/write objects with encoding" do
67
+ store.write("a", "ß"*10_000_000).should == true
68
+ store.read("a").size.should == 10_000_000
69
+ end
70
+
71
+ it "can write/read giant objects" do
72
+ store.write("a", "a"*100_000_000).should == true
73
+ store.read("a").size.should == 100_000_000
74
+ end
75
+
76
+ it "uses necessary keys" do
77
+ store.write("a", "a"*5_000_000)
78
+ store.store.keys.should == ["a_0", "a_1", "a_2", "a_3", "a_4", "a_5"]
79
+ end
80
+
81
+ it "uses read_multi" do
82
+ store.write("a", "a"*5_000_000)
83
+ store.store.should_receive(:read).with("a_0").and_return 5
84
+ store.read("a").size.should == 5_000_000
85
+ end
86
+
87
+ describe "#fetch" do
88
+ it "executes the block on miss" do
89
+ store.fetch("a"){ 1 }.should == 1
90
+ end
91
+
92
+ it "does not execute the block on hit" do
93
+ store.fetch("a"){ 1 }
94
+ store.fetch("a"){ 2 }.should == 1
95
+ end
96
+
97
+ it "passes the options" do
98
+ store.should_receive(:write).with(anything, anything, :expires_in => 111)
99
+ store.fetch("a", :expires_in => 111){ 2 }
100
+ end
101
+
102
+ it "can fetch false" do
103
+ store.fetch("a"){ false }.should == false
104
+ store.read("a").should == false
105
+ end
106
+ end
107
+ end
@@ -0,0 +1 @@
1
+ require "large_object_store"
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: large_object_store
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ana Martinez
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-17 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description:
15
+ email: acemacu@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - .travis.yml
21
+ - Gemfile
22
+ - Gemfile.lock
23
+ - Rakefile
24
+ - Readme.md
25
+ - gem-public_cert.pem
26
+ - large_object_store.gemspec
27
+ - lib/large_object_store.rb
28
+ - lib/large_object_store/version.rb
29
+ - spec/large_object_store_spec.rb
30
+ - spec/spec_helper.rb
31
+ homepage: http://github.com/anamartinez/large_object_store
32
+ licenses:
33
+ - MIT
34
+ post_install_message:
35
+ rdoc_options: []
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ! '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubyforge_project:
52
+ rubygems_version: 1.8.25
53
+ signing_key:
54
+ specification_version: 3
55
+ summary: Store large objects in memcache or others
56
+ test_files: []