leveldb-native 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +68 -0
- data/Rakefile +65 -0
- data/example/snapshot.rb +33 -0
- data/ext/leveldb-native/extconf.rb +5 -0
- data/lib/leveldb-native.rb +156 -0
- data/lib/leveldb-native/version.rb +3 -0
- data/test/test-db-options.rb +156 -0
- data/test/test-db.rb +53 -0
- data/test/test-iterator.rb +104 -0
- data/test/test-snapshot.rb +77 -0
- metadata +68 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 239b4f05b8dfe841e93f81d3c173a0eed17c6c5a
|
4
|
+
data.tar.gz: 5fa95a754b9c3b86912e2564b6f93e62b43bf5c6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2578c6532e99ccfb04b1111fc04d148f1ed5959c56d6ff3c10452b42f964d09ea813171662146782e2db35f647fa9e61a162192da84900cdf1927dcacb252613
|
7
|
+
data.tar.gz: 67f52e24344fb62ee720c680bb78eccb03b2044cdfd3e2f393a8e14493e8bada443d7ab8f6e0b5b327e1a8d2d4bab00658341c9a34dcd64818dcd256d4c3b1ab
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Joel VanderWerf
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
ruby-leveldb-native
|
2
|
+
===================
|
3
|
+
|
4
|
+
A ruby binding to levelDB. It is native in two senses:
|
5
|
+
|
6
|
+
1. Uses libleveldb as a C/C++ ruby extension, rather than through FFI.
|
7
|
+
|
8
|
+
2. Uses the natively installed libleveldb, rather than trying to build and install libleveldb as part of the gem.
|
9
|
+
|
10
|
+
LevelDB
|
11
|
+
-------
|
12
|
+
|
13
|
+
[LevelDB] (http://code.google.com/p/leveldb/) is a persistent key-value store developed at Google.
|
14
|
+
|
15
|
+
Installation
|
16
|
+
------------
|
17
|
+
|
18
|
+
The gem installs in the normal way:
|
19
|
+
|
20
|
+
gem install leveldb-native
|
21
|
+
|
22
|
+
However, you need to have libleveldb installed. It may be available as part of your OS (from debian repos, for example), or you may prefer to install from source. The source packages from google do not have install scripts, but that is easy to fix. Here is a git repo with the necessary fixes to the makefile:
|
23
|
+
|
24
|
+
https://github.com/vjoel/leveldb
|
25
|
+
|
26
|
+
Just follow the instructions in that repo's README to build and install.
|
27
|
+
|
28
|
+
FAQ
|
29
|
+
---
|
30
|
+
|
31
|
+
1. Why not use the [leveldb gem] (https://github.com/DAddYE/leveldb) instead?
|
32
|
+
|
33
|
+
1. Doesn't support the full functionality of snapshots. Snapshots in this gem can only be used to switch the state of the DB object, but not act as independent and concurrent readable views of the database at different points in time.
|
34
|
+
|
35
|
+
2. Tries to maintain its own installation of libleveldb, which may be a different version from the system-wide installation.
|
36
|
+
|
37
|
+
3. Accesses the lib using FFI, which is slower than ruby's native extension architecture. (See benchmarks at the link above.)
|
38
|
+
|
39
|
+
2. Why not use the [leveldb-ruby gem] (https://github.com/wmorgan/leveldb-ruby) instead?
|
40
|
+
|
41
|
+
1. Not maintained regularly.
|
42
|
+
|
43
|
+
2. Tries to maintain its own installation of libleveldb.
|
44
|
+
|
45
|
+
3. No snapshots.
|
46
|
+
|
47
|
+
This gem attempts to maintain compatibility with the leveldb-ruby gem, while adding more features.
|
48
|
+
|
49
|
+
Acknowledgement
|
50
|
+
---------------
|
51
|
+
|
52
|
+
This gem owes much to William Morgan's gem, https://github.com/wmorgan/leveldb-ruby.
|
53
|
+
|
54
|
+
Contact
|
55
|
+
-------
|
56
|
+
|
57
|
+
This project is hosted at https://github.com/vjoel/leveldb-native.
|
58
|
+
|
59
|
+
Joel VanderWerf, vjoel@users.sourceforge.net.
|
60
|
+
|
61
|
+
License and Copyright
|
62
|
+
---------------------
|
63
|
+
|
64
|
+
Copyright (c) 2013, Joel VanderWerf.
|
65
|
+
|
66
|
+
Portions of ext/leveldb-native/leveldb-native.cc are copyright William Morgan.
|
67
|
+
|
68
|
+
License for this project is MIT. See the LICENSE file for the standard MIT license.
|
data/Rakefile
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
PRJ = "leveldb-native"
|
5
|
+
|
6
|
+
def version
|
7
|
+
@version ||= begin
|
8
|
+
require 'leveldb-native/version'
|
9
|
+
warn "LevelDBNative::VERSION not a string" unless
|
10
|
+
LevelDBNative::VERSION.kind_of? String
|
11
|
+
LevelDBNative::VERSION
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def tag
|
16
|
+
@tag ||= "#{PRJ}-#{version}"
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Run unit tests"
|
20
|
+
Rake::TestTask.new :test do |t|
|
21
|
+
t.libs << "lib"
|
22
|
+
t.libs << "ext"
|
23
|
+
t.test_files = FileList["test/*.rb"]
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Commit, tag, and push repo; build and push gem"
|
27
|
+
task :release => "release:is_new_version" do
|
28
|
+
require 'tempfile'
|
29
|
+
|
30
|
+
sh "gem build #{PRJ}.gemspec"
|
31
|
+
|
32
|
+
file = Tempfile.new "template"
|
33
|
+
begin
|
34
|
+
file.puts "release #{version}"
|
35
|
+
file.close
|
36
|
+
sh "git commit --allow-empty -a -v -t #{file.path}"
|
37
|
+
ensure
|
38
|
+
file.close unless file.closed?
|
39
|
+
file.unlink
|
40
|
+
end
|
41
|
+
|
42
|
+
sh "git tag #{tag}"
|
43
|
+
sh "git push"
|
44
|
+
sh "git push --tags"
|
45
|
+
|
46
|
+
sh "gem push #{tag}.gem"
|
47
|
+
end
|
48
|
+
|
49
|
+
namespace :release do
|
50
|
+
desc "Diff to latest release"
|
51
|
+
task :diff do
|
52
|
+
latest = `git describe --abbrev=0 --tags --match '#{PRJ}-*'`.chomp
|
53
|
+
sh "git diff #{latest}"
|
54
|
+
end
|
55
|
+
|
56
|
+
desc "Log to latest release"
|
57
|
+
task :log do
|
58
|
+
latest = `git describe --abbrev=0 --tags --match '#{PRJ}-*'`.chomp
|
59
|
+
sh "git log #{latest}.."
|
60
|
+
end
|
61
|
+
|
62
|
+
task :is_new_version do
|
63
|
+
abort "#{tag} exists; update version!" unless `git tag -l #{tag}`.empty?
|
64
|
+
end
|
65
|
+
end
|
data/example/snapshot.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'leveldb-native'
|
2
|
+
|
3
|
+
db = LevelDBNative::DB.new '/tmp/leveldb-example-snapshot'
|
4
|
+
|
5
|
+
db["a"] = "1"
|
6
|
+
db["b"] = "1"
|
7
|
+
db.delete "c"
|
8
|
+
puts "initialized database to #{db.to_a}"
|
9
|
+
puts
|
10
|
+
|
11
|
+
puts "snapshot:"
|
12
|
+
db.snapshot do |sn|
|
13
|
+
puts "value at a is #{sn["a"]}"
|
14
|
+
sn.each {|k,v| puts " #{k} => #{v}"}
|
15
|
+
end
|
16
|
+
puts
|
17
|
+
|
18
|
+
sn = db.snapshot
|
19
|
+
puts "taking new snapshot"
|
20
|
+
db["b"] = "2"
|
21
|
+
puts "put 'b' => #{db["b"].inspect}"
|
22
|
+
db["c"] = "2"
|
23
|
+
puts "put 'c' => #{db["c"].inspect}"
|
24
|
+
|
25
|
+
puts "snapshot is: #{sn.to_a}"
|
26
|
+
puts "database is: #{db.to_a}"
|
27
|
+
puts
|
28
|
+
|
29
|
+
sn.release
|
30
|
+
puts "relasing snapshot (will now reflect current db state)"
|
31
|
+
puts "snapshot is: #{sn.to_a}"
|
32
|
+
puts "database is: #{db.to_a}"
|
33
|
+
puts
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'leveldb-native/leveldb_native'
|
2
|
+
|
3
|
+
module LevelDBNative
|
4
|
+
class DB
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# Loads or creates a database as necessary, stored on disk at
|
9
|
+
# +pathname+.
|
10
|
+
#
|
11
|
+
# See #make for possible options.
|
12
|
+
def new pathname, options={}
|
13
|
+
make path_string(pathname),
|
14
|
+
options.merge(:create_if_missing => true,
|
15
|
+
:error_if_exists => false)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Creates a new database stored on disk at +pathname+. Raises
|
19
|
+
# LevelDBNative::Error if the database already exists.
|
20
|
+
#
|
21
|
+
# See #make for possible options.
|
22
|
+
def create pathname, options={}
|
23
|
+
make path_string(pathname),
|
24
|
+
options.merge(:create_if_missing => true,
|
25
|
+
:error_if_exists => true)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Loads a database stored on disk at +pathname+. Raises
|
29
|
+
# LevelDBNative::Error unless the database already exists.
|
30
|
+
def load pathname
|
31
|
+
make path_string(pathname),
|
32
|
+
:create_if_missing => false, :error_if_exists => false
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Coerces the argument into a String for use as a filename/-path
|
38
|
+
def path_string pathname
|
39
|
+
File.respond_to?(:path) ? File.path(pathname) : pathname.to_str
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
attr_reader :pathname
|
44
|
+
attr_reader :options
|
45
|
+
|
46
|
+
alias :includes? :exists?
|
47
|
+
alias :contains? :exists?
|
48
|
+
alias :member? :exists?
|
49
|
+
alias :[] :get
|
50
|
+
alias :[]= :put
|
51
|
+
alias :close! :close
|
52
|
+
|
53
|
+
def each(*args, &block)
|
54
|
+
i = iterator(*args)
|
55
|
+
i.each(&block) if block
|
56
|
+
i
|
57
|
+
end
|
58
|
+
|
59
|
+
def iterator(*args); Iterator.new self, *args; end
|
60
|
+
def keys; map {|k, v| k} end
|
61
|
+
def values; map {|k, v| v} end
|
62
|
+
|
63
|
+
# If called with a block, yields a snapshot to the caller, and the
|
64
|
+
# snapshot is released after the block finishes. Otherwise, returns a
|
65
|
+
# snapshot and caller must call #release on the snapshot.
|
66
|
+
def snapshot(*args)
|
67
|
+
sn = Snapshot.new self, *args
|
68
|
+
if block_given?
|
69
|
+
begin
|
70
|
+
yield sn
|
71
|
+
ensure
|
72
|
+
sn.release
|
73
|
+
end
|
74
|
+
else
|
75
|
+
sn
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def inspect
|
80
|
+
"<#{self.class} #{@pathname.inspect}>"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Iterator
|
85
|
+
include Enumerable
|
86
|
+
|
87
|
+
attr_reader :db, :from, :to
|
88
|
+
|
89
|
+
def self.new(db, opts={})
|
90
|
+
make db, opts
|
91
|
+
end
|
92
|
+
|
93
|
+
def keys; map {|k, v| k} end
|
94
|
+
def values; map {|k, v| v} end
|
95
|
+
|
96
|
+
def reversed?; @reversed end
|
97
|
+
def inspect
|
98
|
+
"<#{self.class} #{db.inspect} " +
|
99
|
+
"@from=#{@from.inspect} @to=#{@to.inspect}#{' (reversed)' if @reversed}>"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class WriteBatch
|
104
|
+
class << self
|
105
|
+
private :new
|
106
|
+
end
|
107
|
+
|
108
|
+
alias :[]= :put
|
109
|
+
end
|
110
|
+
|
111
|
+
# Snapshot has the same API as DB, restricted to read access.
|
112
|
+
class Snapshot
|
113
|
+
include Enumerable
|
114
|
+
|
115
|
+
def self.new(db)
|
116
|
+
make db
|
117
|
+
end
|
118
|
+
|
119
|
+
def each(*args, &block)
|
120
|
+
i = iterator(*args)
|
121
|
+
i.each(&block) if block
|
122
|
+
i
|
123
|
+
end
|
124
|
+
|
125
|
+
def get(*args)
|
126
|
+
db.get(*args, snapshot: self)
|
127
|
+
end
|
128
|
+
|
129
|
+
alias :[] :get
|
130
|
+
alias :includes? :exists?
|
131
|
+
alias :contains? :exists?
|
132
|
+
alias :member? :exists?
|
133
|
+
|
134
|
+
def iterator(*args); db.iterator *args, snapshot: self; end
|
135
|
+
def keys; map {|k, v| k} end
|
136
|
+
def values; map {|k, v| v} end
|
137
|
+
|
138
|
+
def inspect
|
139
|
+
"<#{self.class} #{db.inspect} #{' (released)' if released?}>"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
class Options
|
144
|
+
DEFAULT_MAX_OPEN_FILES = 1000
|
145
|
+
DEFAULT_WRITE_BUFFER_SIZE = 4 * 1024 * 1024
|
146
|
+
DEFAULT_BLOCK_SIZE = 4 * 1024
|
147
|
+
DEFAULT_BLOCK_RESTART_INTERVAL = 16
|
148
|
+
DEFAULT_COMPRESSION = LevelDBNative::CompressionType::SnappyCompression
|
149
|
+
|
150
|
+
attr_reader :create_if_missing, :error_if_exists,
|
151
|
+
:block_cache_size, :paranoid_checks,
|
152
|
+
:write_buffer_size, :max_open_files,
|
153
|
+
:block_size, :block_restart_interval,
|
154
|
+
:compression
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'leveldb-native'
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
class TestDBOptions < Minitest::Test
|
6
|
+
include LevelDBNative
|
7
|
+
|
8
|
+
attr_reader :dir
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@dir = Dir.mktmpdir "leveldb-test-db-options-"
|
12
|
+
end
|
13
|
+
|
14
|
+
def teardown
|
15
|
+
FileUtils.remove_entry @dir
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_create_if_missing_behavior
|
19
|
+
assert_raises(Error) do
|
20
|
+
DB.make(dir, {}) # create_if_missing is false
|
21
|
+
end
|
22
|
+
db = DB.make dir, :create_if_missing => true
|
23
|
+
assert db.options.create_if_missing
|
24
|
+
db.close!
|
25
|
+
|
26
|
+
db2 = DB.make dir, {}
|
27
|
+
refute db2.options.create_if_missing
|
28
|
+
db2.close!
|
29
|
+
|
30
|
+
FileUtils.rm_rf dir
|
31
|
+
|
32
|
+
DB.new dir # by default should set create_if_missing to true
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_error_if_exists_behavior
|
36
|
+
db = DB.make dir, :create_if_missing => true
|
37
|
+
refute db.options.error_if_exists
|
38
|
+
db.close!
|
39
|
+
|
40
|
+
assert_raises(Error) do
|
41
|
+
DB.make dir, :create_if_missing => true, :error_if_exists => true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_paranoid_check_default
|
46
|
+
db = DB.new dir
|
47
|
+
refute db.options.paranoid_checks
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_paranoid_check_on
|
51
|
+
db = DB.new dir, :paranoid_checks => true
|
52
|
+
assert db.options.paranoid_checks
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_paranoid_check_off
|
56
|
+
db = DB.new dir, :paranoid_checks => false
|
57
|
+
refute db.options.paranoid_checks
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_write_buffer_size_default
|
61
|
+
db = DB.new dir
|
62
|
+
assert_equal Options::DEFAULT_WRITE_BUFFER_SIZE,
|
63
|
+
db.options.write_buffer_size
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_write_buffer_size
|
67
|
+
db = DB.new dir, :write_buffer_size => 10 * 1042
|
68
|
+
assert_equal (10 * 1042), db.options.write_buffer_size
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_write_buffer_size_invalid
|
72
|
+
assert_raises(TypeError) do
|
73
|
+
DB.new dir, :write_buffer_size => "1234"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_max_open_files_default
|
78
|
+
db = DB.new dir
|
79
|
+
assert_equal Options::DEFAULT_MAX_OPEN_FILES, db.options.max_open_files
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_max_open_files
|
83
|
+
db = DB.new(dir, :max_open_files => 2000)
|
84
|
+
assert_equal db.options.max_open_files, 2000
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_max_open_files_invalid
|
88
|
+
assert_raises(TypeError) do
|
89
|
+
DB.new dir, :max_open_files => "2000"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_cache_size_default
|
94
|
+
db = DB.new dir
|
95
|
+
assert_nil db.options.block_cache_size
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_cache_size
|
99
|
+
db = DB.new dir, :block_cache_size => 10 * 1024 * 1024
|
100
|
+
assert_equal (10 * 1024 * 1024), db.options.block_cache_size
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_cache_size_invalid
|
104
|
+
assert_raises(TypeError) do
|
105
|
+
DB.new dir, :block_cache_size => false
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_block_size_default
|
110
|
+
db = DB.new dir
|
111
|
+
assert_equal Options::DEFAULT_BLOCK_SIZE, db.options.block_size
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_block_size
|
115
|
+
db = DB.new dir, :block_size => (2 * 1024)
|
116
|
+
assert_equal (2 * 1024), db.options.block_size
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_block_size_invalid
|
120
|
+
assert_raises(TypeError) do
|
121
|
+
DB.new dir, :block_size => true
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_block_restart_interval_default
|
126
|
+
db = DB.new dir
|
127
|
+
assert_equal Options::DEFAULT_BLOCK_RESTART_INTERVAL,
|
128
|
+
db.options.block_restart_interval
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_block_restart_interval
|
132
|
+
db = DB.new dir, :block_restart_interval => 32
|
133
|
+
assert_equal 32, db.options.block_restart_interval
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_block_restart_interval_invalid
|
137
|
+
assert_raises(TypeError) do
|
138
|
+
DB.new dir, :block_restart_interval => "abc"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_compression_default
|
143
|
+
db = DB.new dir
|
144
|
+
assert_equal Options::DEFAULT_COMPRESSION, db.options.compression
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_compression
|
148
|
+
db = DB.new dir, :compression => CompressionType::NoCompression
|
149
|
+
assert_equal CompressionType::NoCompression, db.options.compression
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_compression_invalid_type
|
153
|
+
assert_raises(TypeError) { DB.new dir, :compression => "1234" }
|
154
|
+
assert_raises(TypeError) { DB.new dir, :compression => 999 }
|
155
|
+
end
|
156
|
+
end
|
data/test/test-db.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'leveldb-native'
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
class TestDB < Minitest::Test
|
6
|
+
include LevelDBNative
|
7
|
+
|
8
|
+
attr_reader :db
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@dir = Dir.mktmpdir "leveldb-test-db-"
|
12
|
+
@db = DB.new @dir
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
FileUtils.remove_entry @dir
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_size
|
20
|
+
1000.times { |x| db.put x.to_s, "foo" }
|
21
|
+
assert_equal 1000, db.size
|
22
|
+
1000.times { |x| db.delete x.to_s}
|
23
|
+
assert_equal 0, db.size
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_operations
|
27
|
+
refute db.exists?("k")
|
28
|
+
|
29
|
+
db["k"] = "v"
|
30
|
+
assert_equal "v", db["k"]
|
31
|
+
assert db.exists?("k")
|
32
|
+
|
33
|
+
db.delete "k"
|
34
|
+
assert_equal nil, db["k"]
|
35
|
+
refute db.exists?("k")
|
36
|
+
end
|
37
|
+
|
38
|
+
## how to test that fill_cache, verify_checksums, sync are getting passed to
|
39
|
+
## the C++ lib?
|
40
|
+
|
41
|
+
def test_batch
|
42
|
+
db['k0'] = '0'
|
43
|
+
db['k1'] = '0'
|
44
|
+
|
45
|
+
db.batch do |batch|
|
46
|
+
batch['k0'] = '1'
|
47
|
+
batch.delete 'k1'
|
48
|
+
end
|
49
|
+
|
50
|
+
assert_equal '1', db['k0']
|
51
|
+
refute db.exists? 'k1'
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'leveldb-native'
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
class TestIterator < Minitest::Test
|
6
|
+
include LevelDBNative
|
7
|
+
|
8
|
+
attr_reader :db
|
9
|
+
|
10
|
+
KEYS = (0..9).map {|ki| ki.to_s}
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@dir = Dir.mktmpdir "leveldb-test-iterator-"
|
14
|
+
@db = DB.new @dir
|
15
|
+
|
16
|
+
KEYS.each_with_index do |k, vi|
|
17
|
+
db[k] = vi.to_s
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def teardown
|
22
|
+
FileUtils.remove_entry @dir
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_each
|
26
|
+
db.each_with_index do |(k, v), i|
|
27
|
+
assert_equal i.to_s, k
|
28
|
+
assert_equal i.to_s, v
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_from
|
33
|
+
k = 5
|
34
|
+
a = db.each(:from => k.to_s).keys
|
35
|
+
assert_equal KEYS[k..-1], a
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_to
|
39
|
+
k = 5
|
40
|
+
a = db.each(:to => k.to_s).keys
|
41
|
+
assert_equal KEYS[0..k], a
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_from_to
|
45
|
+
k0 = 5; k1 = 8
|
46
|
+
a = db.each(:from => k0.to_s, :to => k1.to_s).keys
|
47
|
+
assert_equal KEYS[k0..k1], a
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_reverse_each
|
51
|
+
assert_equal KEYS.reverse, db.each(:reversed => true).keys
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_reverse_from
|
55
|
+
k = 5
|
56
|
+
a = db.each(:reversed => true, :from => k.to_s).keys
|
57
|
+
assert_equal KEYS[0..k].reverse, a
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_reverse_to
|
61
|
+
k = 5
|
62
|
+
a = db.each(:reversed => true, :to => k.to_s).keys
|
63
|
+
assert_equal KEYS[k..-1].reverse, a
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_reverse_from_to
|
67
|
+
k0 = 5; k1 = 8
|
68
|
+
a = db.each(:reversed => true, :from => k1.to_s, :to => k0.to_s).keys
|
69
|
+
assert_equal KEYS[k0..k1].reverse, a
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_iterator_peek
|
73
|
+
iter = db.iterator
|
74
|
+
assert_equal %w(0 0), iter.peek, iter.invalid_reason
|
75
|
+
assert_equal %w(0 0), iter.peek, iter.invalid_reason
|
76
|
+
assert_nil iter.scan
|
77
|
+
assert_equal %w(1 1), iter.peek, iter.invalid_reason
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_iterator_init_with_default_options
|
81
|
+
iter = db.iterator
|
82
|
+
assert_equal db, iter.db
|
83
|
+
assert_nil iter.from
|
84
|
+
assert_nil iter.to
|
85
|
+
refute iter.reversed?
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_iterator_init_with_options
|
89
|
+
iter = db.iterator :from => 'abc', :to => 'def', :reversed => true
|
90
|
+
assert_equal db,iter.db
|
91
|
+
assert_equal 'abc', iter.from
|
92
|
+
assert_equal 'def', iter.to
|
93
|
+
assert iter.reversed?
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_iterator_not_valid
|
97
|
+
iter = db.iterator from: KEYS[-1]
|
98
|
+
assert_nil iter.invalid_reason
|
99
|
+
assert_equal %w{9 9}, iter.next
|
100
|
+
assert_equal -1, iter.invalid_reason
|
101
|
+
assert_equal nil, iter.next
|
102
|
+
assert_equal -1, iter.invalid_reason
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'leveldb-native'
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
class TestSnapshot < Minitest::Test
|
6
|
+
include LevelDBNative
|
7
|
+
|
8
|
+
attr_reader :db
|
9
|
+
|
10
|
+
KEYS = %w{ k1 k2 k3 }
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@dir = Dir.mktmpdir "leveldb-test-snapshot-"
|
14
|
+
@db = DB.new @dir
|
15
|
+
|
16
|
+
KEYS.each do |k|
|
17
|
+
db[k] = "0"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def teardown
|
22
|
+
FileUtils.remove_entry @dir
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_get
|
26
|
+
sn = db.snapshot
|
27
|
+
KEYS.each do |k|
|
28
|
+
db[k] = "1"
|
29
|
+
end
|
30
|
+
KEYS.each do |k|
|
31
|
+
assert_equal "0", sn[k]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_iterator
|
36
|
+
sn = db.snapshot
|
37
|
+
KEYS.each do |k|
|
38
|
+
db[k] = "1"
|
39
|
+
end
|
40
|
+
sn.each do |k,v|
|
41
|
+
assert_equal "0", v
|
42
|
+
end
|
43
|
+
assert_equal KEYS, sn.keys
|
44
|
+
assert_equal ["0"], sn.values.uniq
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_exists
|
48
|
+
sn = db.snapshot
|
49
|
+
db["new"] = "new"
|
50
|
+
db.delete "k1"
|
51
|
+
assert_equal false, sn.exists?( "new" )
|
52
|
+
assert_equal true, sn.exists?( "k1" )
|
53
|
+
assert_equal true, db.exists?( "new" )
|
54
|
+
assert_equal false, db.exists?( "k1" )
|
55
|
+
|
56
|
+
sn.release
|
57
|
+
assert_equal true, sn.exists?( "new" )
|
58
|
+
assert_equal false, sn.exists?( "k1" )
|
59
|
+
assert_equal true, db.exists?( "new" )
|
60
|
+
assert_equal false, db.exists?( "k1" )
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_release
|
64
|
+
sn = db.snapshot
|
65
|
+
KEYS.each do |k|
|
66
|
+
db[k] = "1"
|
67
|
+
end
|
68
|
+
|
69
|
+
assert_equal false, sn.released?
|
70
|
+
sn.release
|
71
|
+
assert_equal true, sn.released?
|
72
|
+
|
73
|
+
sn.each do |k,v|
|
74
|
+
assert_equal "1", v
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: leveldb-native
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joel VanderWerf
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-07 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Ruby binding to LevelDB.
|
14
|
+
email: vjoel@users.sourceforge.net
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files:
|
18
|
+
- README.md
|
19
|
+
- LICENSE
|
20
|
+
files:
|
21
|
+
- README.md
|
22
|
+
- LICENSE
|
23
|
+
- Rakefile
|
24
|
+
- lib/leveldb-native.rb
|
25
|
+
- lib/leveldb-native/version.rb
|
26
|
+
- ext/leveldb-native/extconf.rb
|
27
|
+
- example/snapshot.rb
|
28
|
+
- test/test-db.rb
|
29
|
+
- test/test-db-options.rb
|
30
|
+
- test/test-snapshot.rb
|
31
|
+
- test/test-iterator.rb
|
32
|
+
homepage: https://github.com/vjoel/ruby-leveldb-native
|
33
|
+
licenses:
|
34
|
+
- MIT
|
35
|
+
metadata: {}
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options:
|
38
|
+
- "--quiet"
|
39
|
+
- "--line-numbers"
|
40
|
+
- "--inline-source"
|
41
|
+
- "--title"
|
42
|
+
- LevelDB Native
|
43
|
+
- "--main"
|
44
|
+
- README.md
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements: []
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 2.1.10
|
60
|
+
signing_key:
|
61
|
+
specification_version: 4
|
62
|
+
summary: Ruby binding to LevelDB.
|
63
|
+
test_files:
|
64
|
+
- test/test-db.rb
|
65
|
+
- test/test-db-options.rb
|
66
|
+
- test/test-snapshot.rb
|
67
|
+
- test/test-iterator.rb
|
68
|
+
has_rdoc:
|