rocksdb-ruby 0.2.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,38 +5,52 @@
5
5
  #include "rocksdb_iterator_rb.h"
6
6
 
7
7
  extern "C" {
8
+ VALUE cRocksdb;
8
9
  VALUE cRocksdb_iterator;
9
10
 
11
+ VALUE cRocksdb_database_closed;
12
+ VALUE cRocksdb_iterator_closed;
13
+ VALUE cRocksdb_status_error;
14
+ VALUE cRocksdb_readonly;
15
+
10
16
  void Init_RocksDB(){
11
-
12
- VALUE cRocksdb;
13
17
  VALUE cRocksdb_db;
14
18
  VALUE cRocksdb_write_batch;
15
19
  VALUE cRocksdb_read_options;
16
20
  VALUE cRocksdb_write_options;
17
21
  VALUE cRocksdb_status;
18
-
22
+ VALUE cRocksdb_error;
23
+
24
+ VALUE rb_cStandardError = rb_const_get(rb_cObject, rb_intern("StandardError"));
25
+
19
26
  cRocksdb = rb_define_module("RocksDB");
27
+ rb_define_singleton_method(cRocksdb, "library_version", (METHOD)rocksdb_version, 0);
28
+
29
+ cRocksdb_error = rb_define_class_under(cRocksdb, "Error", rb_cStandardError);
30
+
31
+ cRocksdb_readonly = rb_define_class_under(cRocksdb, "ReadOnly", cRocksdb_error);
32
+ cRocksdb_status_error = rb_define_class_under(cRocksdb, "StatusError", cRocksdb_error);
33
+ cRocksdb_database_closed = rb_define_class_under(cRocksdb, "DatabaseClosed", cRocksdb_error);
34
+ cRocksdb_iterator_closed = rb_define_class_under(cRocksdb, "IteratorClosed", cRocksdb_error);
35
+
20
36
  cRocksdb_db = rb_define_class_under(cRocksdb, "DB", rb_cObject);
21
37
  rb_define_alloc_func(cRocksdb_db, db_alloc);
22
38
 
23
- rb_define_private_method(cRocksdb_db, "__initialize", (METHOD)rocksdb_db_init, -1);
24
- rb_define_private_method(cRocksdb_db, "__initialize2", (METHOD)rocksdb_db_init2, -1);
39
+ rb_define_private_method(cRocksdb_db, "__initialize", (METHOD)rocksdb_db_init, 3);
40
+ rb_define_method(cRocksdb_db, "property", (METHOD)rocksdb_db_property, 1);
41
+ rb_define_method(cRocksdb_db, "options_strings", (METHOD)rocksdb_db_options, 0);
25
42
  rb_define_method(cRocksdb_db, "put", (METHOD)rocksdb_db_put, 2);
26
43
  rb_define_method(cRocksdb_db, "write", (METHOD)rocksdb_db_write, 1);
27
- rb_define_method(cRocksdb_db, "get", (METHOD)rocksdb_db_get, 1);
28
- rb_define_method(cRocksdb_db, "multi_get", (METHOD)rocksdb_db_multi_get, 1);
44
+ rb_define_method(cRocksdb_db, "get_one", (METHOD)rocksdb_db_get, 1);
45
+ rb_define_method(cRocksdb_db, "get_many", (METHOD)rocksdb_db_multi_get, 1);
29
46
  rb_define_method(cRocksdb_db, "delete", (METHOD)rocksdb_db_delete, 1);
30
47
  rb_define_method(cRocksdb_db, "exists?", (METHOD)rocksdb_db_exists, 1);
31
- rb_define_private_method(cRocksdb_db, "__close", (METHOD)rocksdb_db_close, 0);
48
+ rb_define_method(cRocksdb_db, "close", (METHOD)rocksdb_db_close, 0);
32
49
  rb_define_method(cRocksdb_db, "debug", (METHOD)rocksdb_db_debug, 0);
33
- rb_define_method(cRocksdb_db, "new_iterator", (METHOD)rocksdb_db_new_iterator, 0);
50
+ rb_define_method(cRocksdb_db, "to_iterator", (METHOD)rocksdb_db_to_iterator, 0);
34
51
  rb_define_method(cRocksdb_db, "compact", (METHOD)rocksdb_db_compact, -1);
35
-
36
- rb_define_method(cRocksdb_db, "iterator", (METHOD)rocksdb_db_each, 0);
37
- rb_define_method(cRocksdb_db, "each_index", (METHOD)rocksdb_db_each_index, 0);
38
- rb_define_method(cRocksdb_db, "each_with_index", (METHOD)rocksdb_db_each_with_index, 0);
39
- rb_define_method(cRocksdb_db, "reverse_each", (METHOD)rocksdb_db_reverse_each, 0);
52
+ rb_define_method(cRocksdb_db, "writable?", (METHOD)rocksdb_db_is_writable, 0);
53
+ rb_define_method(cRocksdb_db, "open?", (METHOD)rocksdb_db_is_open, 0);
40
54
 
41
55
  cRocksdb_write_batch = rb_define_class_under(cRocksdb, "Batch", rb_cObject);
42
56
  rb_define_alloc_func(cRocksdb_write_batch, batch_alloc);
@@ -46,18 +60,40 @@ extern "C" {
46
60
 
47
61
  cRocksdb_iterator = rb_define_class_under(cRocksdb, "Iterator", rb_cObject);
48
62
  rb_define_alloc_func(cRocksdb_iterator, rocksdb_iterator_alloc);
63
+
64
+ rb_define_method(cRocksdb_iterator, "valid?", (METHOD)rocksdb_iterator_valid, 0);
49
65
  rb_define_method(cRocksdb_iterator, "seek_to_first", (METHOD)rocksdb_iterator_seek_to_first, 0);
50
66
  rb_define_method(cRocksdb_iterator, "seek_to_last", (METHOD)rocksdb_iterator_seek_to_last, 0);
51
67
  rb_define_method(cRocksdb_iterator, "seek", (METHOD)rocksdb_iterator_seek, 1);
52
- rb_define_method(cRocksdb_iterator, "valid", (METHOD)rocksdb_iterator_valid, 0);
68
+ #if ROCKSDB_VERSION >= 41100
69
+ rb_define_method(cRocksdb_iterator, "seek_for_previous", (METHOD)rocksdb_iterator_seek_for_prev, 1);
70
+ #endif
71
+ rb_define_method(cRocksdb_iterator, "next", (METHOD)rocksdb_iterator_next, 0);
72
+ rb_define_method(cRocksdb_iterator, "previous", (METHOD)rocksdb_iterator_prev, 0);
73
+
53
74
  rb_define_method(cRocksdb_iterator, "key", (METHOD)rocksdb_iterator_key, 0);
54
75
  rb_define_method(cRocksdb_iterator, "value", (METHOD)rocksdb_iterator_value, 0);
55
- rb_define_method(cRocksdb_iterator, "next", (METHOD)rocksdb_iterator_next, 0);
76
+
56
77
  rb_define_method(cRocksdb_iterator, "close", (METHOD)rocksdb_iterator_close, 0);
57
78
 
79
+ rb_define_method(cRocksdb_iterator, "each", (METHOD)rocksdb_iterator_each, 0);
80
+ rb_define_method(cRocksdb_iterator, "reverse_each", (METHOD)rocksdb_iterator_reverse_each, 0);
81
+ rb_define_method(cRocksdb_iterator, "each_key", (METHOD)rocksdb_iterator_each_key, 0);
82
+ rb_define_method(cRocksdb_iterator, "reverse_each_key", (METHOD)rocksdb_iterator_reverse_each_key, 0);
83
+ rb_define_method(cRocksdb_iterator, "each_pair", (METHOD)rocksdb_iterator_each_pair, 0);
84
+ rb_define_method(cRocksdb_iterator, "reverse_each_pair", (METHOD)rocksdb_iterator_reverse_each_pair, 0);
85
+
86
+ rb_define_method(cRocksdb_iterator, "each_prefix", (METHOD)rocksdb_iterator_each_prefix, 1);
87
+ rb_define_method(cRocksdb_iterator, "each_range", (METHOD)rocksdb_iterator_each_range, 2);
88
+
58
89
  cRocksdb_status = rb_define_class_under(cRocksdb, "Status", rb_cObject);
59
90
  cRocksdb_read_options = rb_define_class_under(cRocksdb, "ReadOptions", rb_cObject);
60
91
  cRocksdb_write_options = rb_define_class_under(cRocksdb, "WriteOptions", rb_cObject);
92
+ }
61
93
 
94
+ VALUE rocksdb_version(VALUE self){
95
+ VALUE v_version;
96
+ v_version = rb_sprintf("%i.%i.%i", ROCKSDB_MAJOR, ROCKSDB_MINOR, ROCKSDB_PATCH);
97
+ return v_version;
62
98
  }
63
99
  }
@@ -1,25 +1,48 @@
1
1
  #include "rocksdb/db.h"
2
2
  #include "rocksdb/write_batch.h"
3
+ #include "rocksdb/version.h"
3
4
 
4
5
  #ifndef RUBY_ROCKSDB_H
5
6
  #define RUBY_ROCKSDB_H 1
6
7
 
8
+ #ifndef NDEBUG
9
+ #include <iostream>
10
+ #define TRACE(Out) (std::cerr << __FILE__ << ":" << __LINE__ << "(" << __func__ << ") " << Out << std::endl);
11
+ #else
12
+ #define TRACE(Out)
13
+ #endif
7
14
 
8
- extern "C" {
15
+ #define ROCKSDB_VERSION (ROCKSDB_MAJOR * 10000 \
16
+ + ROCKSDB_MINOR * 100 \
17
+ + ROCKSDB_PATCH)
9
18
 
10
19
  #include <ruby.h>
20
+ extern "C" {
21
+
22
+ #define SLICE_TO_RB_STRING(slice) (rb_enc_str_new(slice.data(), slice.size(), rb_utf8_encoding()))
23
+ #define SLICE_FROM_RB_VALUE(entity) ({ VALUE _string = StringValue((entity)); rocksdb::Slice(RSTRING_PTR(_string), RSTRING_LEN(_string)); })
24
+ #define STRING_FROM_RB_VALUE(entity) ({ VALUE _string = StringValue(entity); std::string(RSTRING_PTR(_string), RSTRING_LEN(_string)); })
25
+
26
+ extern VALUE cRocksdb;
11
27
  extern VALUE cRocksdb_iterator;
12
-
28
+
29
+ extern VALUE cRocksdb_database_closed;
30
+ extern VALUE cRocksdb_iterator_closed;
31
+ extern VALUE cRocksdb_status_error;
32
+ extern VALUE cRocksdb_readonly;
33
+
13
34
  typedef VALUE (*METHOD)(...);
14
-
15
- struct rocksdb_pointer{
35
+
36
+ struct rocksdb_pointer{
16
37
  rocksdb::DB* db;
17
38
  bool readonly;
18
39
  };
19
40
 
20
- struct rocksdb_iterator_pointer{
41
+ struct rocksdb_iterator_pointer{
21
42
  rocksdb::Iterator* it;
43
+ rocksdb_pointer* db_pointer;
22
44
  };
23
-
45
+
46
+ VALUE rocksdb_version(VALUE self);
24
47
  }
25
48
  #endif
@@ -1,3 +1 @@
1
- extern "C" {
2
1
  #include <ruby.h>
3
- }
@@ -1,3 +1 @@
1
- extern "C" {
2
1
  #include <ruby.h>
3
- }
data/lib/rocksdb.rb CHANGED
@@ -1,63 +1,82 @@
1
1
  require "rocksdb/RocksDB" # the c extension
2
2
  require "rocksdb/ruby/version"
3
3
 
4
+ require 'forwardable'
5
+
4
6
  module RocksDB
5
- class DBError < StandardError; end
6
- class DB
7
+ class Error < StandardError; end
8
+ class ReadOnly < RocksDB::Error; end
9
+ class StatusError < RocksDB::Error; end
10
+ class DatabaseClosed < RocksDB::Error; end
11
+ class IteratorClosed < RocksDB::Error; end
12
+
13
+ class Iterator
7
14
  include Enumerable
15
+ end
8
16
 
9
- @@cache = {}
10
-
11
- class << self
12
- def get_instance *args
13
- readonly = !!(args[1] && args[1][:readonly])
14
- key = args[0]
15
-
16
- if readonly
17
- return new(*args)
18
- end
19
- unless @@cache[key]
20
- @@cache[key] = new(*args)
21
- end
22
- @@cache[key]
23
- end
17
+ class << self
18
+ def open(db_path, db_options = "")
19
+ ::RocksDB::DB.new(db_path, db_options, readonly: false)
24
20
  end
25
-
26
- def initialize *args
27
- readonly = !!(args[1] && args[1][:readonly])
28
- @key = args[0]
29
-
30
- if !readonly and @@cache[@key]
31
- __initialize2(*args)
32
- raise DBError.new("error #{@key.to_s} alread open")
33
- end
34
21
 
35
- __initialize(*args)
36
- unless readonly
37
- @@cache[@key] = self
22
+ def open_readonly(db_path, db_options = "")
23
+ ::RocksDB::DB.new(db_path, db_options, readonly: true)
24
+ end
25
+ end
26
+
27
+ class DB
28
+ extend Forwardable
29
+
30
+ def initialize(path, rocksdb_options = "", options = {})
31
+ is_readonly = options[:readonly] || false
32
+
33
+ if rocksdb_options.is_a? Hash
34
+ is_readonly = rocksdb_options.delete(:readonly)
35
+
36
+ rocksdb_options = rocksdb_options.map do |key, value|
37
+ [key, value].join("=")
38
+ end.join(";")
38
39
  end
40
+
41
+ __initialize(path, is_readonly, rocksdb_options.to_s)
39
42
  end
40
43
 
41
- def close
42
- @@cache.delete(@key)
43
- __close
44
+ def get(*args)
45
+ args.flatten!
46
+
47
+ if args.size == 1
48
+ get_one args.first
49
+ else
50
+ get_many args
51
+ end
44
52
  end
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(&block)
54
- if block_given?
55
- self.each_with_index do |key, value|
56
- block.call(value)
53
+
54
+ def options
55
+ options_strings.each_with_object({}) do |(option_group, value), result|
56
+ pairs = value.split(/;\s*/)
57
+ pairs.map do |pair|
58
+ key, value = pair.split("=")
59
+ result[key] = value
57
60
  end
58
- else
59
- self.iterator
60
61
  end
61
62
  end
63
+
64
+ alias_method :includes?, :exists?
65
+ alias_method :contains?, :exists?
66
+ alias_method :member?, :exists?
67
+ alias_method :member?, :exists?
68
+ alias_method :[], :get
69
+ alias_method :[]=, :put
70
+ alias_method :close!, :close
71
+
72
+ def_delegators :to_iterator,
73
+ :each, :reverse_each, :each_key, :reverse_each_key,
74
+ :each_pair, :reverse_each_pair,
75
+ :each_prefix, :each_range
76
+
77
+ alias_method :each_index, :each_key
78
+ alias_method :each_with_index, :each_pair
62
79
  end
63
80
  end
81
+
82
+ require 'rocksdb/ruby/deprecated'
@@ -0,0 +1,29 @@
1
+ # Deprecated methods, kept for backward compatibility
2
+ module RocksDB
3
+ class DBError < ::RocksDB::Error; end;
4
+
5
+ class Iterator
6
+ extend Gem::Deprecate
7
+
8
+ alias_method :valid, :valid?
9
+ deprecate :valid, :valid?, 2019, 12
10
+ end
11
+
12
+ class DB
13
+ extend Gem::Deprecate
14
+
15
+ alias_method :new_iterator, :to_iterator
16
+ deprecate :new_iterator, :to_iterator, 2019, 12
17
+
18
+ def is_readonly?
19
+ !writable?
20
+ end
21
+ deprecate :is_readonly?, :writable?, 2019, 12
22
+
23
+ alias_method :is_open?, :open?
24
+ deprecate :is_open?, :open?, 2019, 12
25
+
26
+ alias_method :multi_get, :get_many
27
+ deprecate :multi_get, :get_many, 2019, 12
28
+ end
29
+ end
@@ -1,5 +1,5 @@
1
1
  module Rocksdb
2
2
  module Ruby
3
- VERSION = "0.2.0"
3
+ VERSION = "1.0.1"
4
4
  end
5
5
  end
data/rocksdb-ruby.gemspec CHANGED
@@ -12,14 +12,15 @@ Gem::Specification.new do |spec|
12
12
  spec.email = ["isamu.a@gmail.com"]
13
13
  spec.summary = %q{A simple RocksDB library for Ruby}
14
14
  spec.homepage = "https://github.com/isamu/rocksdb-ruby"
15
- spec.license = "mit"
15
+ spec.license = "MIT"
16
16
 
17
17
  spec.files = `git ls-files`.split($/)
18
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
20
  spec.require_paths = ["ext", "lib"]
21
21
 
22
- spec.add_development_dependency "bundler", "~> 1.3"
23
- spec.add_development_dependency "rake"
24
- spec.add_development_dependency "rspec"
22
+ spec.add_development_dependency "bundler", "~> 2.0"
23
+ spec.add_development_dependency "rake", "~> 12.0"
24
+ spec.add_development_dependency "rspec", "~> 3.0"
25
+ spec.add_development_dependency "rspec-core", "~> 3.0"
25
26
  end
data/spec/db_null_spec.rb CHANGED
@@ -3,38 +3,38 @@ require 'spec_helper'
3
3
  require "rocksdb"
4
4
 
5
5
  describe RocksDB do
6
- before do
7
- @rocksdb = RocksDB::DB.new "/tmp/file"
8
- end
6
+ context "null-terminated strings" do
7
+ before do
8
+ @rocksdb = RocksDB.open temp_db_path
9
9
 
10
- it 'should get null contained data' do
11
- @aaa = "aa\0aa"
10
+ @rocksdb.put("test:text1\0a", "hello")
11
+ @rocksdb.put("test:plain", "he\0llo")
12
+ @rocksdb.put("test:null\0a", "he\0llo")
13
+ @rocksdb.put("test:nullmulti1\0a", "a\0a1")
14
+ @rocksdb.put("test:nullmulti2\0a", "b\0a2")
15
+ @rocksdb.put("test:nullmulti3\0a", "c\0a3")
16
+ end
12
17
 
13
- @rocksdb.put("test:null", @aaa)
14
- expect(@rocksdb.get("test:null")).to eq "aa\0aa"
15
- end
18
+ it 'should get key with null bytes' do
19
+ expect(@rocksdb.get("test:text1\0a")).to eq "hello"
20
+ end
16
21
 
17
- it 'should get from null contained key' do
18
- @key = "test:aa\0aa"
19
- @rocksdb.put(@key, "aaa")
20
- expect(@rocksdb.get(@key)).to eq "aaa"
21
-
22
- @key = "test:aa"
23
- expect(@rocksdb.get(@key)).to eq nil
22
+ it 'should get value with null bytes' do
23
+ expect(@rocksdb.get("test:plain")).to eq "he\0llo"
24
+ end
24
25
 
25
- end
26
+ it 'should get key and value with null bytes' do
27
+ expect(@rocksdb.get("test:null\0a")).to eq "he\0llo"
28
+ end
26
29
 
27
- it 'should get multi data' do
28
- @rocksdb.put("test:nullmulti1\0a", "a\01")
29
- @rocksdb.put("test:nullmulti2\0a", "b\02")
30
- @rocksdb.put("test:nullmulti3\0a", "c\03")
30
+ it 'should get all pairs' do
31
+ expect(@rocksdb.get("test:nullmulti1\0a", "test:nullmulti2\0a", "test:nullmulti3\0a")).to eq ["a\0a1", "b\0a2", "c\0a3"]
31
32
 
32
- expect(@rocksdb.multi_get(["test:nullmulti1\0a", "test:nullmulti2\0a", "test:nullmulti3\0a"])).to eq ["a\01", "b\02", "c\03"]
33
- expect(@rocksdb.multi_get(["test:nullmulti1", "test:nullmulti2", "test:nullmulti3"])).to eq ["", "", ""]
34
- end
35
-
36
- after do
37
- @rocksdb.close
33
+ expect(@rocksdb.get("test:nullmulti1", "test:nullmulti2", "test:nullmulti3")).to eq [nil, nil, nil]
34
+ end
35
+
36
+ after do
37
+ @rocksdb.close
38
+ end
38
39
  end
39
-
40
40
  end
@@ -3,16 +3,51 @@ require 'spec_helper'
3
3
  require "rocksdb"
4
4
 
5
5
  describe RocksDB do
6
- before do
7
- @rocksdb = RocksDB::DB.new "/tmp/file3", {:max_bytes_for_level_base => 10485760, :max_grandparent_overlap_factor => 20}
8
- end
6
+ context "options" do
7
+ let(:rocksdb) { RocksDB.open temp_db_path, "WAL_size_limit_MB=16" }
8
+
9
+ it "returns RocksDB options as a hash" do
10
+ expect(rocksdb.options).to be_a Hash
11
+ end
12
+
13
+ it "returns database options" do
14
+ expect(rocksdb.options).to include("use_fsync")
15
+ end
9
16
 
10
- it 'should get data' do
11
- @rocksdb.put("test:multi_db", "10")
12
- expect(@rocksdb.get("test:multi_db")).to eq "10"
17
+ it "returns column family options" do
18
+ expect(rocksdb.options).to include("table_factory")
19
+ end
13
20
  end
14
21
 
15
- after do
16
- @rocksdb.close
22
+ context "open" do
23
+ it 'should work without options' do
24
+ rocksdb = RocksDB.open temp_db_path
25
+
26
+ expect(rocksdb).to be_open
27
+ end
28
+
29
+ it 'should set valid string options' do
30
+ rocksdb = RocksDB.open temp_db_path, "WAL_size_limit_MB=16"
31
+
32
+ expect(rocksdb.options["WAL_size_limit_MB"])
33
+ .to eq "16"
34
+ end
35
+
36
+ it 'should set valid hash options' do
37
+ rocksdb = RocksDB.open temp_db_path, WAL_size_limit_MB: "42"
38
+
39
+ expect(rocksdb.options["WAL_size_limit_MB"])
40
+ .to eq "42"
41
+ end
42
+
43
+ it 'should not set invalid option' do
44
+ expect { RocksDB.open temp_db_path, "Omg_totaly_fake=4" }
45
+ .to raise_error(RocksDB::StatusError)
46
+ end
47
+
48
+ it 'should not segfault on gibberish' do
49
+ expect { RocksDB.open temp_db_path, "%28324!@4912=4AAS\00DAD2-;1421" }
50
+ .to raise_error(RocksDB::StatusError)
51
+ end
17
52
  end
18
53
  end