ninjudd-bdb 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/ext/bdb.h ADDED
@@ -0,0 +1,104 @@
1
+
2
+ #ifndef BDB2_H
3
+ #define BDB2_H
4
+
5
+ #include <ruby.h>
6
+
7
+ #ifdef stat
8
+ #undef stat
9
+ #endif
10
+
11
+ #ifdef close
12
+ #undef close
13
+ #endif
14
+
15
+ #ifdef rename
16
+ #undef rename
17
+ #endif
18
+
19
+ #include <version.h>
20
+ #include <db.h>
21
+
22
+ #define NOTXN NULL
23
+
24
+ #ifdef OPEN_MAX
25
+ #define LMAXFD OPEN_MAX
26
+ #else
27
+ #ifdef FOPEN_MAX
28
+ #define LMAXFD FOPEN_MAX
29
+ #endif
30
+ #endif
31
+ #ifndef LMAXFD
32
+ #error "No max fd define available."
33
+ #endif
34
+
35
+ #define FNLEN 40
36
+
37
+ #define filename_copy(fp,fv) \
38
+ strncpy(fp,RSTRING_PTR(fv),FNLEN);
39
+
40
+ #define filename_dup(fpd,fps) \
41
+ strncpy(fpd,fps,FNLEN);
42
+
43
+ typedef struct s_envh {
44
+ VALUE self;
45
+ DB_ENV *env;
46
+ VALUE adb; /* Ruby array holding opened databases */
47
+ VALUE atxn; /* Ruby array holding open transactions */
48
+ } t_envh;
49
+
50
+ typedef struct s_dbh {
51
+ VALUE self;
52
+ DB *db;
53
+ int db_opened;
54
+ VALUE aproc;
55
+ VALUE sproc; /* key sorting callback */
56
+
57
+ t_envh *env; /* Parent environment, NULL if not opened from one */
58
+ VALUE adbc; /* Ruby array holding opened cursor */
59
+ char filename[FNLEN+1];
60
+ } t_dbh;
61
+
62
+ typedef struct s_dbch {
63
+ VALUE self;
64
+ DBC *dbc;
65
+ t_dbh *db;
66
+ char filename[FNLEN+1];
67
+ } t_dbch;
68
+
69
+ typedef struct s_txnh {
70
+ VALUE self;
71
+ DB_TXN *txn;
72
+ t_envh *env;
73
+ } t_txnh;
74
+
75
+ #define cu(b,m) \
76
+ rb_define_const(b,#m,UINT2NUM(m))
77
+
78
+ #define ci(b,m) \
79
+ rb_define_const(b,#m,INT2NUM(m))
80
+
81
+ #define cs(b,m) \
82
+ rb_define_const(b,#m,rb_str_new2(m))
83
+
84
+ #define simple_set(fname) \
85
+ VALUE db_ ## fname ## _eq(VALUE obj, VALUE v) \
86
+ { \
87
+ rb_ivar_set(obj,fv_ ## fname,v); \
88
+ return obj; \
89
+ }
90
+
91
+ #define attr_writer(fname) \
92
+ VALUE fname ## _writer(VALUE obj, VALUE v) \
93
+ { \
94
+ rb_ivar_set(obj,fv_ ## fname,v); \
95
+ return obj; \
96
+ }
97
+
98
+ #define attr_reader(fname) \
99
+ VALUE fname ## _reader(VALUE obj) \
100
+ { \
101
+ return rb_ivar_get(obj,fv_ ## fname); \
102
+ }
103
+
104
+ #endif
data/ext/extconf.rb ADDED
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env ruby
2
+ require 'mkmf'
3
+
4
+ inc, lib = dir_config('db')
5
+
6
+ # OS X compatibility
7
+ if(PLATFORM =~ /darwin/) then
8
+ # test if Bdb is probably universal
9
+
10
+ filetype = (IO.popen("file #{inc}/../db_dump").readline.chomp rescue nil)
11
+ # if it's not universal, ARCHFLAGS should be set
12
+ if((filetype !~ /universal binary/) && ENV['ARCHFLAGS'].nil?) then
13
+ arch = (IO.popen("uname -m").readline.chomp rescue nil)
14
+ $stderr.write %{
15
+ =========== WARNING ===========
16
+
17
+ You are building this extension on OS X without setting the
18
+ ARCHFLAGS environment variable, and BerkeleyDB does not appear
19
+ to have been built as a universal binary. If you are seeing this
20
+ message, that means that the build will probably fail.
21
+
22
+ Try setting the environment variable ARCHFLAGS
23
+ to '-arch #{arch}' before building.
24
+
25
+ For example:
26
+ (in bash) $ export ARCHFLAGS='-arch #{arch}'
27
+ (in tcsh) % setenv ARCHFLAGS '-arch #{arch}'
28
+
29
+ Then try building again.
30
+
31
+ ===================================
32
+
33
+ }
34
+ # We don't exit here. Who knows? It might build.
35
+ end
36
+ end
37
+
38
+ versions=%w(db-4.7 db-4.6 db-4.5 db-4.4 db-4.3 db-4.2)
39
+ until versions.empty?
40
+ (lib_ok = have_library(versions.shift,'db_version', 'db.h')) && break
41
+ end
42
+
43
+ def create_header
44
+ if File.exist?("bdb_aux._c")
45
+ message("Not writing bdb_aux._c (defines), already exists\n")
46
+ return
47
+ end
48
+
49
+ message("Writing bdb_aux._c (defines), this takes a while\n")
50
+ db_header = $CPPFLAGS.split.select { |f| f =~ /^-I/ }.map { |e|
51
+ f = File.join(e[2..-1], 'db.h')
52
+ File.exists?(f) ? f : nil
53
+ }.select { |e| e }.first
54
+
55
+ n=0
56
+ defines=[]
57
+ File.open(db_header) {|fd|
58
+ File.open("bdb_aux._c","w") {|hd|
59
+ hd.puts("/* This file automatically generated by extconf.rb */\n")
60
+ fd.each_line {|l|
61
+ if l =~ %r{^#define\s+(DBC?_\w*)\s+([^\/]*)\s*(.*?)(\/\*.*)?$}
62
+ name = $1
63
+ value = $2
64
+ if macro_defined?(name,"#include <db.h>")
65
+ case value
66
+ when /^"/
67
+ hd.print(%Q{cs(mBdb,%s);\n}%[name])
68
+ when /^\(?(0x|\d)/
69
+ hd.print(%Q{cu(mBdb,%s);\n}%[name])
70
+ when /^\(?-/
71
+ hd.print(%Q{ci(mBdb,%s);\n}%[name])
72
+ else
73
+ $stderr.puts "don't know how to handle #{name} #{value.strip}, guessing UINT"
74
+ hd.print(%Q{cu(mBdb,%s);\n}%[name])
75
+ end
76
+ n+=1
77
+ end
78
+ end
79
+ }
80
+ }
81
+ message("\nwrote #{n} defines\n")
82
+ }
83
+ end
84
+
85
+ if lib_ok
86
+ create_header
87
+ create_makefile('bdb')
88
+ else
89
+ $stderr.puts("cannot create Makefile")
90
+ exit 1
91
+ end
@@ -0,0 +1,150 @@
1
+ require 'test_helper'
2
+
3
+ class CursorTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ mkdir File.join(File.dirname(__FILE__), 'tmp')
7
+ @db = Bdb::Db.new
8
+ @db.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'test.db'), nil, Bdb::Db::BTREE, Bdb::DB_CREATE, 0)
9
+ 10.times { |i| @db.put(nil, i.to_s, "data-#{i}", 0)}
10
+ @cursor = @db.cursor(nil, 0)
11
+ end
12
+
13
+ def teardown
14
+ @cursor.close if @cursor
15
+ assert(@db.close(0)) if @db
16
+ rm_rf File.join(File.dirname(__FILE__), 'tmp')
17
+ end
18
+
19
+ def test_get
20
+ key, value = @cursor.get(nil, nil, Bdb::DB_FIRST)
21
+ assert_equal '0', key
22
+ assert_equal 'data-0', value
23
+ end
24
+
25
+ def test_get_range
26
+ keys = []
27
+ key, value = @cursor.get("4", nil, Bdb::DB_SET_RANGE)
28
+ while key and key <= "9"
29
+ keys << key
30
+ key, value = @cursor.get(nil, nil, Bdb::DB_NEXT)
31
+ end
32
+
33
+ assert_equal (4..9).collect {|i| i.to_s}, keys
34
+ end
35
+
36
+ def test_pget
37
+ @db1 = Bdb::Db.new
38
+ @db1.flags = Bdb::DB_DUPSORT
39
+ @db1.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'test1.db'), nil, Bdb::Db::HASH, Bdb::DB_CREATE, 0)
40
+
41
+ @db.associate(nil, @db1, 0, proc { |sdb, key, data| key.split('-')[0] })
42
+
43
+ @db.put(nil, '1234-5678', 'data', 0)
44
+ @db.put(nil, '5678-1234', 'atad', 0)
45
+
46
+ @cursor1 = @db1.cursor(nil, 0)
47
+ key, pkey, value = @cursor1.pget(nil, nil, Bdb::DB_FIRST)
48
+ assert_equal '1234', key
49
+ assert_equal '1234-5678', pkey
50
+ assert_equal 'data', value
51
+
52
+ @cursor1.close
53
+ @db1.close(0)
54
+ end
55
+
56
+ def test_put
57
+ @cursor.put('10_000', 'data-10_000', Bdb::DB_KEYLAST)
58
+ value = @db.get(nil, '10_000', nil, 0)
59
+ assert_equal 'data-10_000', value
60
+ end
61
+
62
+ def test_del
63
+ key, value = @cursor.get(nil, nil, Bdb::DB_FIRST)
64
+ value = @db.get(nil, '0', nil, 0)
65
+ assert_equal '0', key
66
+ assert_equal 'data-0', value
67
+ @cursor.del
68
+ value = @db.get(nil, '0', nil, 0)
69
+ assert_nil value
70
+ end
71
+
72
+ def test_count
73
+ @cursor.get(nil, nil, Bdb::DB_FIRST)
74
+ assert_equal 1, @cursor.count
75
+ end
76
+
77
+ def test_get_all_in_order
78
+ all = []
79
+ while pair = @cursor.get(nil, nil, Bdb::DB_NEXT)
80
+ all << pair.first
81
+ end
82
+ assert_equal (0..9).collect {|i| i.to_s}, all
83
+ end
84
+
85
+ def test_get_all_with_btree_compare
86
+ @db1 = Bdb::Db.new
87
+ @db1.btree_compare = proc {|db, key1, key2| key2 <=> key1}
88
+ @db1.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'test1.db'), nil, Bdb::Db::BTREE, Bdb::DB_CREATE, 0)
89
+ 10.times { |i| @db1.put(nil, i.to_s, "data-#{i}", 0)}
90
+ @cursor1 = @db1.cursor(nil, 0)
91
+
92
+ all = []
93
+ while pair = @cursor1.get(nil, nil, Bdb::DB_NEXT)
94
+ all << pair.first
95
+ end
96
+ assert_equal (0..9).collect {|i| i.to_s}.reverse, all
97
+ @cursor1.close
98
+ @db1.close(0)
99
+ end
100
+
101
+ def test_btree_compare_raises_if_fixnum_not_returned
102
+ @db1 = Bdb::Db.new
103
+ @db1.btree_compare = proc {|db, key1, key2| key1}
104
+ @db1.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'test1.db'), nil, Bdb::Db::BTREE, Bdb::DB_CREATE, 0)
105
+
106
+ assert_raises(TypeError) do
107
+ @db1.put(nil, "no", "way", 0)
108
+ @db1.put(nil, "ho", "say", 0)
109
+ end
110
+ @db1.close(Bdb::DB_NOSYNC)
111
+ end
112
+
113
+ def test_join
114
+ @personnel_db = Bdb::Db.new
115
+ @personnel_db.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'personnel_db.db'), nil, Bdb::Db::HASH, Bdb::DB_CREATE, 0)
116
+
117
+ @names_db = Bdb::Db.new
118
+ @names_db.flags = Bdb::DB_DUPSORT
119
+ @names_db.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'names_db.db'), nil, Bdb::Db::HASH, Bdb::DB_CREATE, 0)
120
+
121
+ @jobs_db = Bdb::Db.new
122
+ @jobs_db.flags = Bdb::DB_DUPSORT
123
+ @jobs_db.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'jobs_db.db'), nil, Bdb::Db::HASH, Bdb::DB_CREATE, 0)
124
+
125
+ [{:ssn => '111-11-1111', :lastname => 'Smith', :job => 'welder'},
126
+ {:ssn => '222-22-2222', :lastname => 'Jones', :job => 'welder'},
127
+ {:ssn => '333-33-3333', :lastname => 'Smith', :job => 'painter'}].each do |e|
128
+ @personnel_db.put(nil, e[:ssn], Marshal.dump([e[:ssn], e[:lastname], e[:job]]), 0)
129
+ @names_db.put(nil, e[:lastname], e[:ssn], 0)
130
+ @jobs_db.put(nil, e[:job], e[:ssn], 0)
131
+ end
132
+
133
+ @name_cursor = @names_db.cursor(nil, 0)
134
+ @name_cursor.get('Smith', nil, Bdb::DB_SET)
135
+ assert_equal 2, @name_cursor.count
136
+ @job_cursor = @jobs_db.cursor(nil, 0)
137
+ @job_cursor.get('welder', nil, Bdb::DB_SET)
138
+ assert_equal 2, @job_cursor.count
139
+ @personnel_cursor = @personnel_db.join([@name_cursor, @job_cursor], 0)
140
+ assert_equal '111-11-1111', @personnel_cursor.get(nil, nil, 0).first
141
+
142
+ @personnel_cursor.close
143
+ @name_cursor.close
144
+ @job_cursor.close
145
+
146
+ @jobs_db.close(0)
147
+ @names_db.close(0)
148
+ @personnel_db.close(0)
149
+ end
150
+ end
data/test/db_test.rb ADDED
@@ -0,0 +1,157 @@
1
+ require 'test_helper'
2
+
3
+ class DbTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ mkdir File.join(File.dirname(__FILE__), 'tmp')
7
+ @db = Bdb::Db.new
8
+ @db.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'test.db'), nil, Bdb::Db::BTREE, Bdb::DB_CREATE, 0)
9
+ end
10
+
11
+ def teardown
12
+ assert(@db.close(0)) if @db
13
+ rm_rf File.join(File.dirname(__FILE__), 'tmp')
14
+ end
15
+
16
+ def test_put_and_get
17
+ @db.put(nil, 'key', 'data', 0)
18
+ result = @db.get(nil, 'key', nil, 0)
19
+ assert_equal 'data', result
20
+ end
21
+
22
+ def test_del
23
+ @db.put(nil, 'key', 'data', 0)
24
+ result = @db.get(nil, 'key', nil, 0)
25
+ assert_equal 'data', result
26
+ @db.del(nil, 'key', 0)
27
+ result = @db.get(nil, 'key', nil, 0)
28
+ assert_nil result
29
+ end
30
+
31
+ def test_flags_set_and_get
32
+ @db1 = Bdb::Db.new
33
+ @db1.flags = Bdb::DB_DUPSORT
34
+ assert Bdb::DB_DUPSORT, @db1.flags
35
+ end
36
+
37
+ def test_associate_and_pget
38
+ @db1 = Bdb::Db.new
39
+ @db1.flags = Bdb::DB_DUPSORT
40
+ @db1.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'test1.db'), nil, Bdb::Db::HASH, Bdb::DB_CREATE, 0)
41
+
42
+ @db.associate(nil, @db1, 0, proc { |sdb, key, data| key.split('-')[0] })
43
+
44
+ @db.put(nil, '1234-5678', 'data', 0)
45
+ @db.put(nil, '5678-1234', 'atad', 0)
46
+
47
+ result = @db.get(nil, '1234-5678', nil, 0)
48
+ assert_equal 'data', result
49
+ result = @db1.get(nil, '5678', nil, 0)
50
+ assert_equal 'atad', result
51
+
52
+ result = @db1.pget(nil, '1234', nil, 0)
53
+ assert_equal ['1234-5678', 'data'], result
54
+
55
+ @db1.close(0)
56
+ end
57
+
58
+ def test_associate_with_multiple_keys
59
+ @db1 = Bdb::Db.new
60
+ @db1.flags = Bdb::DB_DUPSORT
61
+ @db1.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'test1.db'), nil, Bdb::Db::HASH, Bdb::DB_CREATE, 0)
62
+
63
+ @db.associate(nil, @db1, 0, proc { |sdb, key, data| key.split('-') })
64
+
65
+ @db.put(nil, '1234-5678', 'data', 0)
66
+ @db.put(nil, '8765-4321', 'atad', 0)
67
+
68
+ result = @db.get(nil, '1234-5678', nil, 0)
69
+ assert_equal 'data', result
70
+ result = @db1.get(nil, '5678', nil, 0)
71
+ assert_equal 'data', result
72
+ result = @db1.get(nil, '1234', nil, 0)
73
+ assert_equal 'data', result
74
+ result = @db1.get(nil, '8765', nil, 0)
75
+ assert_equal 'atad', result
76
+ result = @db1.get(nil, '4321', nil, 0)
77
+ assert_equal 'atad', result
78
+
79
+ @db1.close(0)
80
+ end
81
+
82
+ def test_aset_and_aget
83
+ @db['key'] = 'data'
84
+ result = @db.get(nil, 'key', nil, 0)
85
+ assert_equal 'data', result
86
+ result = @db['key']
87
+ assert_equal 'data', result
88
+ @db['key'] = 'data1'
89
+ result = @db['key']
90
+ assert_equal 'data1', result
91
+ end
92
+
93
+ def test_get_byteswapped
94
+ @db.get_byteswapped
95
+ end
96
+
97
+ def test_get_type
98
+ assert_equal Bdb::Db::BTREE, @db.get_type
99
+ end
100
+
101
+ def test_remove
102
+ @db1 = Bdb::Db.new
103
+ @db1.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'other_test.db'), nil, Bdb::Db::BTREE, Bdb::DB_CREATE, 0)
104
+ @db1.close(0)
105
+ Bdb::Db.new.remove(File.join(File.dirname(__FILE__), 'tmp', 'other_test.db'), nil, 0)
106
+ assert !File.exists?(File.join(File.dirname(__FILE__), 'tmp', 'other_test.db'))
107
+ end
108
+
109
+ def test_key_range
110
+ 10.times { |i| @db.put(nil, i.to_s, 'data', 0) }
111
+ @db.key_range(nil, '2', 0)
112
+ end
113
+
114
+ def test_rename
115
+ @db1 = Bdb::Db.new
116
+ @db1.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'other_test.db'), nil, Bdb::Db::BTREE, Bdb::DB_CREATE, 0)
117
+ @db1.close(0)
118
+ assert Bdb::Db.new.rename(File.join(File.dirname(__FILE__), 'tmp', 'other_test.db'), nil, File.join(File.dirname(__FILE__), 'tmp', 'other2_test.db'), 0)
119
+ assert File.exists?(File.join(File.dirname(__FILE__), 'tmp', 'other2_test.db'))
120
+ end
121
+
122
+ def test_pagesize_get_and_set
123
+ @db1 = Bdb::Db.new
124
+ @db1.pagesize = 1024
125
+ assert_equal 1024, @db1.pagesize
126
+ end
127
+
128
+ def test_h_ffactor_get_and_set
129
+ @db1 = Bdb::Db.new
130
+ @db1.h_ffactor = 5
131
+ assert_equal 5, @db1.h_ffactor
132
+ end
133
+
134
+ def test_h_nelem_get_and_set
135
+ @db1 = Bdb::Db.new
136
+ @db1.h_nelem = 10_000
137
+ assert_equal 10_000, @db1.h_nelem
138
+ end
139
+
140
+ def test_sync
141
+ assert @db.sync
142
+ end
143
+
144
+ def test_truncate
145
+ @db.put(nil, 'key', 'data', 0)
146
+ result = @db.get(nil, 'key', nil, 0)
147
+ assert_equal 'data', result
148
+ @db.truncate(nil)
149
+ result = @db.get(nil, 'key', nil, 0)
150
+ assert_nil result
151
+ end
152
+
153
+ def test_compact
154
+ assert @db.compact(nil, nil, nil, nil, 0)
155
+ end
156
+
157
+ end