rocksdb-ruby 0.2.2 → 1.0.2

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.
@@ -5,40 +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
- rb_define_method(cRocksdb_db, "is_readonly?", (METHOD)rocksdb_db_is_readonly, 0);
36
- rb_define_method(cRocksdb_db, "is_open?", (METHOD)rocksdb_db_is_open, 0);
37
-
38
- rb_define_method(cRocksdb_db, "iterator", (METHOD)rocksdb_db_each, 0);
39
- rb_define_method(cRocksdb_db, "each_index", (METHOD)rocksdb_db_each_index, 0);
40
- rb_define_method(cRocksdb_db, "each_with_index", (METHOD)rocksdb_db_each_with_index, 0);
41
- 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);
42
54
 
43
55
  cRocksdb_write_batch = rb_define_class_under(cRocksdb, "Batch", rb_cObject);
44
56
  rb_define_alloc_func(cRocksdb_write_batch, batch_alloc);
@@ -48,18 +60,40 @@ extern "C" {
48
60
 
49
61
  cRocksdb_iterator = rb_define_class_under(cRocksdb, "Iterator", rb_cObject);
50
62
  rb_define_alloc_func(cRocksdb_iterator, rocksdb_iterator_alloc);
63
+
64
+ rb_define_method(cRocksdb_iterator, "valid?", (METHOD)rocksdb_iterator_valid, 0);
51
65
  rb_define_method(cRocksdb_iterator, "seek_to_first", (METHOD)rocksdb_iterator_seek_to_first, 0);
52
66
  rb_define_method(cRocksdb_iterator, "seek_to_last", (METHOD)rocksdb_iterator_seek_to_last, 0);
53
67
  rb_define_method(cRocksdb_iterator, "seek", (METHOD)rocksdb_iterator_seek, 1);
54
- 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
+
55
74
  rb_define_method(cRocksdb_iterator, "key", (METHOD)rocksdb_iterator_key, 0);
56
75
  rb_define_method(cRocksdb_iterator, "value", (METHOD)rocksdb_iterator_value, 0);
57
- rb_define_method(cRocksdb_iterator, "next", (METHOD)rocksdb_iterator_next, 0);
76
+
58
77
  rb_define_method(cRocksdb_iterator, "close", (METHOD)rocksdb_iterator_close, 0);
59
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
+
60
89
  cRocksdb_status = rb_define_class_under(cRocksdb, "Status", rb_cObject);
61
90
  cRocksdb_read_options = rb_define_class_under(cRocksdb, "ReadOptions", rb_cObject);
62
91
  cRocksdb_write_options = rb_define_class_under(cRocksdb, "WriteOptions", rb_cObject);
92
+ }
63
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;
64
98
  }
65
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
- }
@@ -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.2"
3
+ VERSION = "1.0.2"
4
4
  end
5
5
  end
data/lib/rocksdb.rb CHANGED
@@ -1,61 +1,80 @@
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
- if !readonly and @@cache[@key]
30
- __initialize2(*args)
31
- raise DBError.new("error #{@key.to_s} alread open")
32
- end
33
- __initialize(*args)
34
- unless readonly
35
- @@cache[@key] = self
21
+
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
+ rocksdb_options = rocksdb_options.map do |key, value|
35
+ [key, value].join("=")
36
+ end.join(";")
36
37
  end
38
+
39
+ __initialize(path, is_readonly, rocksdb_options.to_s)
37
40
  end
38
41
 
39
- def close
40
- @@cache.delete(@key)
41
- __close
42
+ def get(*args)
43
+ args.flatten!
44
+
45
+ if args.size == 1
46
+ get_one args.first
47
+ else
48
+ get_many args
49
+ end
42
50
  end
43
-
44
- alias :includes? :exists?
45
- alias :contains? :exists?
46
- alias :member? :exists?
47
- alias :[] :get
48
- alias :[]= :put
49
- alias :close! :close
50
-
51
- def each(&block)
52
- if block_given?
53
- self.each_with_index do |key, value|
54
- block.call(value)
51
+
52
+ def options
53
+ options_strings.each_with_object({}) do |(option_group, value), result|
54
+ pairs = value.split(/;\s*/)
55
+ pairs.map do |pair|
56
+ key, value = pair.split("=")
57
+ result[key] = value
55
58
  end
56
- else
57
- self.iterator
58
59
  end
59
60
  end
61
+
62
+ alias_method :includes?, :exists?
63
+ alias_method :contains?, :exists?
64
+ alias_method :member?, :exists?
65
+ alias_method :member?, :exists?
66
+ alias_method :[], :get
67
+ alias_method :[]=, :put
68
+ alias_method :close!, :close
69
+
70
+ def_delegators :to_iterator,
71
+ :each, :reverse_each, :each_key, :reverse_each_key,
72
+ :each_pair, :reverse_each_pair,
73
+ :each_prefix, :each_range
74
+
75
+ alias_method :each_index, :each_key
76
+ alias_method :each_with_index, :each_pair
60
77
  end
61
78
  end
79
+
80
+ require 'rocksdb/ruby/deprecated'
data/rocksdb-ruby.gemspec CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.require_paths = ["ext", "lib"]
21
21
 
22
22
  spec.add_development_dependency "bundler", "~> 2.0"
23
- spec.add_development_dependency 'rake', '~> 0'
24
- spec.add_development_dependency "rspec", '~> 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