ninjudd-bdb 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2008 Dan Janowski <danj@3skel.com>, Matt Bauer <bauer@pedalbrain.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,95 @@
1
+ h1. Bdb
2
+
3
+ Ruby bindings for Berkeley DB versions 4.2-4.7.
4
+
5
+ h2. Download
6
+
7
+ Currently this library is available via git at:
8
+
9
+ <pre>
10
+ git://github.com/mattbauer/bdb.git
11
+ </pre>
12
+
13
+ h2. Installation
14
+
15
+ h3. From Git
16
+
17
+ You can check out the latest source from git:
18
+
19
+ <pre>
20
+ git clone git://github.com/mattbauer/bdb.git
21
+ </pre>
22
+
23
+ h3. As a Gem
24
+
25
+ At the moment this library is not available on Rubyforge. To install it as a
26
+ gem, do the following (for custom compiled version 4.7):
27
+
28
+ <pre>
29
+ sudo env ARCHFLAGS="-arch i386" gem install mattbauer-bdb --source http://gems.github.com -- --with-db-dir=/usr/local/BerkeleyDB.4.7
30
+ </pre>
31
+
32
+ For Berkeley DB v4.6 installed from MacPorts do the following:
33
+
34
+ <pre>
35
+ sudo env ARCHFLAGS="-arch i386" gem install mattbauer-bdb --source http://gems.github.com -- --with-db-include=/opt/local/include/db46 --with-db-lib=/opt/local/lib/db46
36
+ </pre>
37
+
38
+ This assumes you're on OS X and BerkeleyDB wasn't compiled as a universal binary.
39
+
40
+ h2. Sample Usage
41
+
42
+ <pre>
43
+ env = Bdb::Env.new(0)
44
+ env_flags = Bdb::DB_CREATE | # Create the environment if it does not already exist.
45
+ Bdb::DB_INIT_TXN | # Initialize transactions
46
+ Bdb::DB_INIT_LOCK | # Initialize locking.
47
+ Bdb::DB_INIT_LOG | # Initialize logging
48
+ Bdb::DB_INIT_MPOOL # Initialize the in-memory cache.
49
+ env.open(File.join(File.dirname(__FILE__), 'tmp'), env_flags, 0);
50
+
51
+ db = env.db
52
+ db.open(nil, 'db1.db', nil, Bdb::Db::BTREE, Bdb::DB_CREATE | Bdb::DB_AUTO_COMMIT, 0)
53
+
54
+ txn = env.txn_begin(nil, 0)
55
+ db.put(txn, 'key', 'value', 0)
56
+ txn.commit(0)
57
+
58
+ value = db.get(nil, 'key', nil, 0)
59
+
60
+ db.close(0)
61
+ env.close
62
+ </pre>
63
+
64
+ h2. API
65
+
66
+ This interface is most closely based on the DB4 C api and tries to maintain close
67
+ interface proximity. That API is published by Oracle at "http://www.oracle.com/technology/documentation/berkeley-db/db/api_c/frame.html":http://www.oracle.com/technology/documentation/berkeley-db/db/api_c/frame.html.
68
+
69
+ All function arguments systematically omit the leading DB handles and TXN handles.
70
+ A few calls omit the flags parameter when the documentation indicates that no
71
+ flag values are used - cursor.close is one.
72
+
73
+ h2. Notes
74
+
75
+ The defines generator is imperfect and includes some defines that are not
76
+ flags. While it could be improved, it is easier to delete the incorrect ones.
77
+ Thus, if you decide to rebuild the defines, you will need to edit the resulting
78
+ file. This may be necessary if using a different release of DB4 than the ones
79
+ the authors developed against. In nearly every case the defines generator works
80
+ flawlessly.
81
+
82
+ The authors have put all possible caution into ensuring that DB and Ruby cooperate.
83
+ The memory access was one aspect carefully considered. Since Ruby copies
84
+ when doing String#new, all key/data retrieval from DB is done with a 0 flag,
85
+ meaning that DB will be responsible. See "this":http://groups.google.com/group/comp.databases.berkeley-db/browse_frm/thread/4f70a9999b64ce6a/c06b94692e3cbc41?tvc=1&q=dbt+malloc#c06b94692e3cbc41
86
+ news group posting about the effect of that.
87
+
88
+ The only other design consideration of consequence was associate. The prior
89
+ version used a Ruby thread local variable and kept track of the current
90
+ database in use. The authors decided to take a simpler approach since Ruby is green
91
+ threads. A global array stores the VALUE of the Proc for a given association
92
+ by the file descriptor number of the underlying database. This is looked
93
+ up when the first layer callback is made. It would have been better considered
94
+ if DB allowed the passing of a (void *) user data into the alloc that would
95
+ be supplied during callback. So far this design has not produced any problems.
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/testtask'
5
+
6
+ load 'bdb.gemspec'
7
+
8
+ Rake::GemPackageTask.new(BDB_SPEC) do |pkg|
9
+ pkg.need_tar = true
10
+ end
11
+
12
+ task :default => "test"
13
+
14
+ desc "Clean"
15
+ task :clean do
16
+ include FileUtils
17
+ Dir.chdir('ext') do
18
+ rm(Dir.glob('*') - ['bdb.c', 'bdb.h', 'extconf.rb'])
19
+ end
20
+ rm_rf 'pkg'
21
+ end
22
+
23
+ desc "Run tests"
24
+ Rake::TestTask.new("test") do |t|
25
+ t.libs.concat ["test", "ext"]
26
+ t.pattern = 'test/*_test.rb'
27
+ t.verbose = true
28
+ t.warning = true
29
+ end
30
+
31
+ task :doc => [:rdoc]
32
+ namespace :doc do
33
+ Rake::RDocTask.new do |rdoc|
34
+ files = ["README", "lib/**/*.rb"]
35
+ rdoc.rdoc_files.add(files)
36
+ rdoc.main = "README.textile"
37
+ rdoc.title = "Bdb Docs"
38
+ rdoc.rdoc_dir = "doc"
39
+ rdoc.options << "--line-numbers" << "--inline-source"
40
+ end
41
+ end
data/bdb.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ BDB_SPEC = Gem::Specification.new do |s|
2
+ s.platform = Gem::Platform::RUBY
3
+ s.required_ruby_version = '>=1.8.4'
4
+ s.name = "bdb"
5
+ s.version = "0.0.2"
6
+ s.authors = ["Matt Bauer", "Dan Janowski"]
7
+ s.email = "bauer@pedalbrain.com"
8
+ s.summary = "A Ruby interface to BerkeleyDB"
9
+ s.files = ['bdb.gemspec',
10
+ 'ext/bdb.c',
11
+ 'ext/bdb.h',
12
+ 'ext/extconf.rb',
13
+ 'LICENSE',
14
+ 'README.textile',
15
+ 'Rakefile']
16
+ s.test_files = ['test/cursor_test.rb',
17
+ 'test/db_test.rb',
18
+ 'test/env_test.rb',
19
+ 'test/stat_test.rb',
20
+ 'test/test_helper.rb',
21
+ 'test/txn_test.rb']
22
+ s.extensions = ["ext/extconf.rb"]
23
+
24
+ s.homepage = "http://github.com/mattbauer/bdb"
25
+
26
+ s.require_paths = ["lib", "ext"]
27
+ s.has_rdoc = false
28
+ end
data/ext/bdb.c ADDED
@@ -0,0 +1,2964 @@
1
+ /*
2
+ * Ruby library that wraps the Sleepycat Berkeley DB.
3
+ *
4
+ * Developed against 4.3/4.4. No support for prior versions.
5
+ *
6
+ */
7
+
8
+ #include <bdb.h>
9
+ #include <stdio.h>
10
+
11
+ #define LMEMFLAG 0
12
+ #define NOFLAGS 0
13
+ #undef DEBUG_DB
14
+
15
+ #ifdef HAVE_STDARG_PROTOTYPES
16
+ #include <stdarg.h>
17
+ #define va_init_list(a,b) va_start(a,b)
18
+ #else
19
+ #include <varargs.h>
20
+ #define va_init_list(a,b) va_start(a)
21
+ #endif
22
+
23
+ VALUE mBdb; /* Top level module */
24
+ VALUE cDb; /* DBT class */
25
+ VALUE cDbStat; /* db status class, not specialized for DBTYPE */
26
+ VALUE cEnv; /* Environment class */
27
+ VALUE cTxn; /* Transaction class */
28
+ VALUE cCursor; /* Cursors */
29
+ VALUE cTxnStat; /* Transaction Status class */
30
+ VALUE cTxnStatActive; /* Active Transaction Status class */
31
+ VALUE eDbError;
32
+
33
+ static ID fv_call,fv_uniq,fv_err_new,fv_err_code,fv_err_msg;
34
+
35
+ /*
36
+ * Document-class: Bdb::DbError
37
+ *
38
+ * Errors generated by methods under the Bdb hierarchy will be
39
+ * of this class unless Ruby itself raises the error.
40
+ *
41
+ */
42
+
43
+ static void
44
+ #ifdef HAVE_STDARG_PROTOTYPES
45
+ raise_error(int code, const char *fmt, ...)
46
+ #else
47
+ raise_error(code,fmt,va_alist)
48
+ int code;
49
+ const char *fmt;
50
+ va_dcl
51
+ #endif
52
+ {
53
+ va_list args;
54
+ char buf[1024];
55
+ VALUE exc;
56
+ VALUE argv[2];
57
+
58
+ va_init_list(args,fmt);
59
+ vsnprintf(buf,1024,fmt,args);
60
+ va_end(args);
61
+
62
+ argv[0]=rb_str_new2(buf);
63
+ argv[1]=INT2NUM(code);
64
+
65
+ exc=rb_class_new_instance(2,argv,eDbError);
66
+ rb_exc_raise(exc);
67
+ }
68
+
69
+ /*
70
+ * An error can only be generated internally
71
+ */
72
+ VALUE err_initialize(VALUE obj, VALUE message, VALUE code)
73
+ {
74
+ VALUE args[1];
75
+ args[0]=message;
76
+ rb_call_super(1,args);
77
+ return rb_ivar_set(obj,fv_err_code,code);
78
+ }
79
+
80
+ /*
81
+ * call-seq:
82
+ * err.code() -> Bdb error code integer
83
+ *
84
+ */
85
+ VALUE err_code(VALUE obj)
86
+ {
87
+ return rb_ivar_get(obj,fv_err_code);
88
+ }
89
+
90
+ static void db_free(t_dbh *dbh)
91
+ {
92
+ #ifdef DEBUG_DB
93
+ if ( RTEST(ruby_debug) )
94
+ fprintf(stderr,"%s/%d %s 0x%x\n",__FILE__,__LINE__,"db_free cleanup!",dbh);
95
+ #endif
96
+
97
+ if (dbh) {
98
+ if (dbh->db) {
99
+ if (dbh->db_opened == 1)
100
+ dbh->db->close(dbh->db,NOFLAGS);
101
+ if ( RTEST(ruby_debug) && dbh->filename[0] != '\0')
102
+ fprintf(stderr,"%s/%d %s %p %s\n",__FILE__,__LINE__,
103
+ "db_free database was still open!",dbh->db,dbh->filename);
104
+ dbh->db=NULL;
105
+ }
106
+ free(dbh);
107
+ }
108
+ }
109
+
110
+ static void db_mark(t_dbh *dbh)
111
+ {
112
+ if ( dbh == NULL ) return;
113
+ if ( ! NIL_P(dbh->aproc) )
114
+ rb_gc_mark(dbh->aproc);
115
+ if ( dbh->env )
116
+ rb_gc_mark(dbh->env->self);
117
+ if ( ! NIL_P(dbh->adbc) )
118
+ rb_gc_mark(dbh->adbc);
119
+ }
120
+
121
+ static void dbc_mark(t_dbch *dbch)
122
+ {
123
+ if (dbch->db)
124
+ rb_gc_mark(dbch->db->self);
125
+ }
126
+ static void dbc_free(void *p)
127
+ {
128
+ t_dbch *dbch;
129
+ dbch=(t_dbch *)p;
130
+
131
+ #ifdef DEBUG_DB
132
+ if ( RTEST(ruby_debug) )
133
+ fprintf(stderr,"%s/%d %s 0x%x\n",__FILE__,__LINE__,
134
+ "dbc_free cleanup!",p);
135
+ #endif
136
+
137
+ if ( dbch ) {
138
+ if ( dbch->dbc ) {
139
+ dbch->dbc->c_close(dbch->dbc);
140
+ if ( RTEST(ruby_debug) )
141
+ fprintf(stderr,"%s/%d %s %p %s\n",__FILE__,__LINE__,
142
+ "dbc_free cursor was still open!",p,dbch->filename);
143
+ }
144
+ free(p);
145
+ }
146
+ }
147
+
148
+ VALUE
149
+ db_alloc(VALUE klass)
150
+ {
151
+ return Data_Wrap_Struct(klass,db_mark,db_free,0);
152
+ }
153
+
154
+ VALUE db_init_aux(VALUE obj,t_envh * eh)
155
+ {
156
+ DB *db;
157
+ t_dbh *dbh;
158
+ int rv;
159
+
160
+ /* This excludes possible use of X/Open Transaction Mgr */
161
+ rv = db_create(&db,(eh)?eh->env:NULL,NOFLAGS);
162
+ if (rv != 0) {
163
+ raise_error(rv, "db_new failure: %s",db_strerror(rv));
164
+ }
165
+
166
+ #ifdef DEBUG_DB
167
+ db->set_errfile(db,stderr);
168
+ #endif
169
+
170
+ dbh=ALLOC(t_dbh);
171
+ if (DATA_PTR(obj)) {
172
+ /* if called from env_db, the data ptr has not been allocated,
173
+ * was freeing 0x0 */
174
+ db_free(DATA_PTR(obj));
175
+ }
176
+ DATA_PTR(obj)=dbh;
177
+ dbh->db=db;
178
+ dbh->self=obj;
179
+ dbh->env=eh;
180
+ dbh->aproc=Qnil;
181
+ dbh->sproc=Qnil;
182
+ memset(&(dbh->filename),0,FNLEN+1);
183
+
184
+ dbh->adbc=Qnil;
185
+
186
+ if (dbh->env) {
187
+ #ifdef DEBUG_DB
188
+ fprintf(stderr,"Adding db to env 0x%x 0x%x\n",obj,dbh);
189
+ #endif
190
+ rb_ary_push(dbh->env->adb,obj);
191
+ }
192
+
193
+ return obj;
194
+ }
195
+
196
+ /*
197
+ * Document-class: Bdb::Db
198
+ *
199
+ */
200
+
201
+ VALUE db_initialize(VALUE obj)
202
+ {
203
+ return db_init_aux(obj,NULL);
204
+ }
205
+
206
+ /*
207
+ * call-seq:
208
+ * db.open(txn_object,disk_file,logical_db,db_type,flags,mode) -> value
209
+ *
210
+ * open a database. disk file is file path. logical_db is
211
+ * a named database within that file, which will be created under
212
+ * conditions noted by DB.
213
+ *
214
+ * db_type is one of the constants:
215
+ * Bdb::DB::BTREE
216
+ * Bdb::DB::HASH
217
+ * Bdb::DB::RECNO
218
+ * Bdb::DB::QUEUE
219
+ * Bdb::DB::UNKNOWN
220
+ *
221
+ * unknown will open an already existing db in the mode created
222
+ */
223
+ VALUE db_open(VALUE obj, VALUE vtxn, VALUE vdisk_file,
224
+ VALUE vlogical_db,
225
+ VALUE vdbtype, VALUE vflags, VALUE vmode)
226
+ {
227
+ t_dbh *dbh;
228
+ int rv;
229
+ t_txnh *txn=NOTXN;
230
+ u_int32_t flags=0;
231
+ DBTYPE dbtype=DB_UNKNOWN;
232
+ char *logical_db=NULL;
233
+ long len;
234
+ int mode=0;
235
+
236
+ if ( ! NIL_P(vflags) )
237
+ flags=NUM2UINT(vflags);
238
+
239
+ if ( ! NIL_P(vtxn) ) {
240
+ Data_Get_Struct(vtxn,t_txnh,txn);
241
+ if (!txn->txn)
242
+ raise(0, "txn is closed");
243
+ }
244
+
245
+ if ( TYPE(vlogical_db)==T_STRING && RSTRING_LEN(vlogical_db) > 0 )
246
+ logical_db=StringValueCStr(vlogical_db);
247
+
248
+ if ( FIXNUM_P(vdbtype) ) {
249
+ dbtype=NUM2INT(vdbtype);
250
+ if ( dbtype < DB_BTREE || dbtype > DB_UNKNOWN ) {
251
+ raise_error(0,"db_open Bad access type: %d",dbtype);
252
+ return Qnil;
253
+ }
254
+ }
255
+
256
+ if ( TYPE(vdisk_file)!=T_STRING || RSTRING_LEN(vdisk_file) < 1 ) {
257
+ raise_error(0,"db_open Bad disk file name");
258
+ return Qnil;
259
+ }
260
+
261
+ if ( ! NIL_P(vmode) )
262
+ mode=NUM2INT(vmode);
263
+
264
+ Data_Get_Struct(obj,t_dbh,dbh);
265
+ if ( ! NIL_P(dbh->adbc) )
266
+ raise_error(0,"db handle already opened");
267
+
268
+ dbh->db->app_private=dbh;
269
+ rv = dbh->db->open(dbh->db,txn?txn->txn:NULL,
270
+ StringValueCStr(vdisk_file),
271
+ logical_db,
272
+ dbtype,flags,mode);
273
+ if (rv != 0) {
274
+ raise_error(rv,"db_open failure: %s(%d)",db_strerror(rv),rv);
275
+ }
276
+ filename_copy(dbh->filename,vdisk_file)
277
+ dbh->adbc=rb_ary_new();
278
+ dbh->db_opened = 1;
279
+ return obj;
280
+ }
281
+
282
+ /*
283
+ * call-seq:
284
+ * db.flags=value
285
+ *
286
+ * set database flags based on DB constants.
287
+ * see http://www.sleepycat.com/docs/api_c/db_set_flags.html
288
+ *
289
+ */
290
+ VALUE db_flags_set(VALUE obj, VALUE vflags)
291
+ {
292
+ t_dbh *dbh;
293
+ int rv;
294
+ u_int32_t flags;
295
+
296
+ flags=NUM2UINT(vflags);
297
+ Data_Get_Struct(obj,t_dbh,dbh);
298
+ if (!dbh->db)
299
+ raise_error(0,"db is closed");
300
+
301
+ rv = dbh->db->set_flags(dbh->db,flags);
302
+ if ( rv != 0 ) {
303
+ raise_error(rv, "db_flag_set failure: %s",db_strerror(rv));
304
+ }
305
+ return vflags;
306
+ }
307
+
308
+ /*
309
+ * call-seq:
310
+ * db.flags -> value
311
+ *
312
+ * get database flags.
313
+ * see http://www.sleepycat.com/docs/api_c/db_get_flags.html
314
+ *
315
+ */
316
+ VALUE db_flags_get(VALUE obj)
317
+ {
318
+ t_dbh *dbh;
319
+ int rv;
320
+ u_int32_t flags;
321
+
322
+ Data_Get_Struct(obj,t_dbh,dbh);
323
+ if (!dbh->db)
324
+ raise_error(0,"db is closed");
325
+
326
+ rv = dbh->db->get_flags(dbh->db,&flags);
327
+ if ( rv != 0 ) {
328
+ raise_error(rv, "db_flag_get failure: %s",db_strerror(rv));
329
+ }
330
+ return INT2NUM(flags);
331
+ }
332
+
333
+ /*
334
+ * call-seq:
335
+ * db.pagesize=value
336
+ *
337
+ * set database flags based on DB constants.
338
+ * see http://www.sleepycat.com/docs/api_c/db_set_flags.html
339
+ *
340
+ */
341
+ VALUE db_pagesize_set(VALUE obj, VALUE vpagesize)
342
+ {
343
+ t_dbh *dbh;
344
+ int rv;
345
+ u_int32_t pagesize;
346
+
347
+ pagesize=NUM2INT(vpagesize);
348
+ Data_Get_Struct(obj,t_dbh,dbh);
349
+ if (!dbh->db)
350
+ raise_error(0,"db is closed");
351
+ rv = dbh->db->set_pagesize(dbh->db,pagesize);
352
+ if ( rv != 0 ) {
353
+ raise_error(rv, "db_pagesize_set failure: %s",db_strerror(rv));
354
+ }
355
+ return vpagesize;
356
+ }
357
+
358
+ /*
359
+ * call-seq:
360
+ * db.pagesize
361
+ *
362
+ * set database flags based on DB constants.
363
+ * see http://www.sleepycat.com/docs/api_c/db_set_flags.html
364
+ *
365
+ */
366
+ VALUE db_pagesize(VALUE obj)
367
+ {
368
+ t_dbh *dbh;
369
+ int rv;
370
+ u_int32_t pagesize;
371
+
372
+ Data_Get_Struct(obj,t_dbh,dbh);
373
+ if (!dbh->db)
374
+ raise_error(0,"db is closed");
375
+ rv = dbh->db->get_pagesize(dbh->db,&pagesize);
376
+ if ( rv != 0 ) {
377
+ raise_error(rv, "db_pagesize_get failure: %s",db_strerror(rv));
378
+ }
379
+ return INT2NUM(pagesize);
380
+ }
381
+
382
+ /*
383
+ * call-seq:
384
+ * db.h_ffactor=value
385
+ *
386
+ * get hash db fill factor
387
+ * formula:
388
+ * (pagesize - 32) / (average_key_size + average_data_size + 8)
389
+ *
390
+ */
391
+ VALUE db_h_ffactor_set(VALUE obj, VALUE vint)
392
+ {
393
+ t_dbh *dbh;
394
+ int rv;
395
+ u_int32_t cint;
396
+
397
+ cint=NUM2INT(vint);
398
+ Data_Get_Struct(obj,t_dbh,dbh);
399
+ if (!dbh->db)
400
+ raise_error(0,"db is closed");
401
+ rv = dbh->db->set_h_ffactor(dbh->db,cint);
402
+ if ( rv != 0 ) {
403
+ raise_error(rv, "db_h_ffactor_set failure: %s",db_strerror(rv));
404
+ }
405
+ return vint;
406
+ }
407
+
408
+ /*
409
+ * call-seq:
410
+ * db.h_ffactor
411
+ *
412
+ * get hash db fill factor
413
+ * formula:
414
+ * (pagesize - 32) / (average_key_size + average_data_size + 8)
415
+ * see http://www.sleepycat.com/docs/api_c/db_set_flags.html
416
+ *
417
+ */
418
+ VALUE db_h_ffactor(VALUE obj)
419
+ {
420
+ t_dbh *dbh;
421
+ int rv;
422
+ u_int32_t cint;
423
+
424
+ Data_Get_Struct(obj,t_dbh,dbh);
425
+ if (!dbh->db)
426
+ raise_error(0,"db is closed");
427
+ rv = dbh->db->get_h_ffactor(dbh->db,&cint);
428
+ if ( rv != 0 ) {
429
+ raise_error(rv, "db_h_ffactor failure: %s",db_strerror(rv));
430
+ }
431
+ return INT2NUM(cint);
432
+ }
433
+ /*
434
+ * call-seq:
435
+ * db.h_nelem=value
436
+ *
437
+ * set estimate number of elements in hash table
438
+ * see http://www.sleepycat.com/docs/api_c/db_set_flags.html
439
+ *
440
+ */
441
+ VALUE db_h_nelem_set(VALUE obj, VALUE vint)
442
+ {
443
+ t_dbh *dbh;
444
+ int rv;
445
+ u_int32_t cint;
446
+
447
+ cint=NUM2INT(vint);
448
+ Data_Get_Struct(obj,t_dbh,dbh);
449
+ if (!dbh->db)
450
+ raise_error(0,"db is closed");
451
+ rv = dbh->db->set_h_nelem(dbh->db,cint);
452
+ if ( rv != 0 ) {
453
+ raise_error(rv, "db_h_nelem_set failure: %s",db_strerror(rv));
454
+ }
455
+ return vint;
456
+ }
457
+
458
+ /*
459
+ * call-seq:
460
+ * db.h_nelem
461
+ *
462
+ * get estimate number of element in the hash table
463
+ * see http://www.sleepycat.com/docs/api_c/db_set_flags.html
464
+ *
465
+ */
466
+ VALUE db_h_nelem(VALUE obj)
467
+ {
468
+ t_dbh *dbh;
469
+ int rv;
470
+ u_int32_t nelem;
471
+
472
+ Data_Get_Struct(obj,t_dbh,dbh);
473
+ if (!dbh->db)
474
+ raise_error(0,"db is closed");
475
+ rv = dbh->db->get_h_nelem(dbh->db,&nelem);
476
+ if ( rv != 0 ) {
477
+ raise_error(rv, "db_h_nelem failure: %s",db_strerror(rv));
478
+ }
479
+ return INT2NUM(nelem);
480
+ }
481
+
482
+ VALUE dbc_close(VALUE);
483
+
484
+ /* call-seq:
485
+ * db.close(flags) -> value
486
+ *
487
+ * close a database handle. Will close open cursors.
488
+ */
489
+ VALUE db_close(VALUE obj, VALUE vflags)
490
+ {
491
+ t_dbh *dbh;
492
+ int rv;
493
+ u_int32_t flags;
494
+ VALUE cur;
495
+
496
+ flags=NUM2UINT(vflags);
497
+ Data_Get_Struct(obj,t_dbh,dbh);
498
+ if ( dbh->db==NULL )
499
+ return Qnil;
500
+
501
+ if (! NIL_P(dbh->adbc) && RARRAY(dbh->adbc)->len > 0 ) {
502
+ rb_warning("%s/%d %s",__FILE__,__LINE__,
503
+ "cursor handles still open");
504
+ while ( (cur=rb_ary_pop(dbh->adbc)) != Qnil ) {
505
+ dbc_close(cur);
506
+ }
507
+ }
508
+
509
+ if ( RTEST(ruby_debug) )
510
+ rb_warning("%s/%d %s 0x%x %s",__FILE__,__LINE__,"db_close!",dbh,
511
+ (dbh->filename==NULL||*(dbh->filename)=='0') ? "unknown" : dbh->filename);
512
+
513
+ rv = dbh->db->close(dbh->db,flags);
514
+ dbh->db=NULL;
515
+ dbh->aproc=Qnil;
516
+ dbh->sproc=Qnil;
517
+ if ( dbh->env ) {
518
+ if ( RTEST(ruby_debug) )
519
+ rb_warning("%s/%d %s 0x%x",__FILE__,__LINE__,"db_close! removing",obj);
520
+ rb_ary_delete(dbh->env->adb,obj);
521
+ dbh->env = NULL;
522
+ }
523
+ if ( rv != 0 ) {
524
+ raise_error(rv, "db_close failure: %s",db_strerror(rv));
525
+ }
526
+ dbh->db_opened = 0;
527
+ return obj;
528
+ }
529
+
530
+ /*
531
+ * call-seq:
532
+ * db.put(txn,key,data,flags) -> self
533
+ *
534
+ * put a key/data pair into the database. returns db. Will
535
+ * raise an error on DB_KEYEXIST but error.code will indicate
536
+ * so it can be easily caught.
537
+ */
538
+ VALUE db_put(VALUE obj, VALUE vtxn, VALUE vkey, VALUE vdata, VALUE vflags)
539
+ {
540
+ t_dbh *dbh;
541
+ int rv;
542
+ u_int32_t flags=0;
543
+ DBT key,data;
544
+ t_txnh *txn=NULL;
545
+
546
+ memset(&key,0,sizeof(DBT));
547
+ memset(&data,0,sizeof(DBT));
548
+
549
+ if ( ! NIL_P(vtxn) ) {
550
+ Data_Get_Struct(vtxn,t_txnh,txn);
551
+ if (!txn->txn)
552
+ raise(0, "txn is closed");
553
+ }
554
+
555
+ if ( ! NIL_P(vflags) )
556
+ flags=NUM2UINT(vflags);
557
+
558
+ Data_Get_Struct(obj,t_dbh,dbh);
559
+ if (!dbh->db)
560
+ raise_error(0,"db is closed");
561
+
562
+ StringValue(vkey);
563
+ key.data = RSTRING_PTR(vkey);
564
+ key.size = RSTRING_LEN(vkey);
565
+ key.flags = LMEMFLAG;
566
+
567
+ StringValue(vdata);
568
+ data.data = RSTRING_PTR(vdata);
569
+ data.size = RSTRING_LEN(vdata);
570
+ data.flags = LMEMFLAG;
571
+
572
+ rv = dbh->db->put(dbh->db,txn?txn->txn:NULL,&key,&data,flags);
573
+ /*
574
+ if (rv == DB_KEYEXIST)
575
+ return Qnil;
576
+ */
577
+ if (rv != 0) {
578
+ raise_error(rv, "db_put fails: %s",db_strerror(rv));
579
+ }
580
+ return obj;
581
+ }
582
+
583
+ /*
584
+ * call-seq:
585
+ * db.get(txn,key,data,flags) -> String(data)
586
+ *
587
+ * get a key/data pair from database. data as a string.
588
+ *
589
+ */
590
+
591
+ VALUE db_get(VALUE obj, VALUE vtxn, VALUE vkey, VALUE vdata, VALUE vflags)
592
+ {
593
+ t_dbh *dbh;
594
+ int rv;
595
+ u_int32_t flags=0;
596
+ DBT key,data;
597
+ VALUE str;
598
+ t_txnh *txn=NULL;
599
+
600
+ memset(&key,0,sizeof(DBT));
601
+ memset(&data,0,sizeof(DBT));
602
+
603
+ if ( ! NIL_P(vtxn) ) {
604
+ Data_Get_Struct(vtxn,t_txnh,txn);
605
+ if (!txn->txn)
606
+ raise(0, "txn is closed");
607
+ }
608
+
609
+ if ( ! NIL_P(vflags) ) {
610
+ flags=NUM2UINT(vflags);
611
+ }
612
+
613
+ Data_Get_Struct(obj,t_dbh,dbh);
614
+ if (!dbh->db)
615
+ raise_error(0,"db is closed");
616
+
617
+ StringValue(vkey);
618
+
619
+ key.data = RSTRING_PTR(vkey);
620
+ key.size = RSTRING_LEN(vkey);
621
+ key.flags = LMEMFLAG;
622
+
623
+ if ( ! NIL_P(vdata) ) {
624
+ StringValue(vdata);
625
+ data.data = RSTRING_PTR(vdata);
626
+ data.size = RSTRING_LEN(vdata);
627
+ data.flags = LMEMFLAG;
628
+ }
629
+
630
+ rv = dbh->db->get(dbh->db,txn?txn->txn:NULL,&key,&data,flags);
631
+ if ( rv == 0 ) {
632
+ return rb_str_new(data.data,data.size);
633
+ } else if (rv == DB_NOTFOUND) {
634
+ return Qnil;
635
+ } else {
636
+ raise_error(rv, "db_get failure: %s",db_strerror(rv));
637
+ }
638
+ return Qnil;
639
+ }
640
+
641
+ /*
642
+ * call-seq:
643
+ * db.pget(txn,key,data,flags) -> [pkey,data]
644
+ *
645
+ * get a key/data pair from database using a secondary index.
646
+ * returns an array with a primary key and the data element.
647
+ *
648
+ */
649
+ VALUE db_pget(VALUE obj, VALUE vtxn, VALUE vkey, VALUE vdata, VALUE vflags)
650
+ {
651
+ t_dbh *dbh;
652
+ int rv;
653
+ u_int32_t flags=0;
654
+ DBT key,data,pkey;
655
+ VALUE str;
656
+ t_txnh *txn=NULL;
657
+
658
+ memset(&key,0,sizeof(DBT));
659
+ memset(&data,0,sizeof(DBT));
660
+ memset(&pkey,0,sizeof(DBT));
661
+
662
+ if ( ! NIL_P(vtxn) ) {
663
+ Data_Get_Struct(vtxn,t_txnh,txn);
664
+ if (!txn->txn)
665
+ raise(0, "txn is closed");
666
+ }
667
+
668
+ if ( ! NIL_P(vflags) ) {
669
+ flags=NUM2UINT(vflags);
670
+ }
671
+
672
+ Data_Get_Struct(obj,t_dbh,dbh);
673
+ if (!dbh->db)
674
+ raise(0, "db is closed");
675
+
676
+ StringValue(vkey);
677
+
678
+ key.data = RSTRING_PTR(vkey);
679
+ key.size = RSTRING_LEN(vkey);
680
+ key.flags = LMEMFLAG;
681
+
682
+ if ( ! NIL_P(vdata) ) {
683
+ StringValue(vdata);
684
+ data.data = RSTRING_PTR(vdata);
685
+ data.size = RSTRING_LEN(vdata);
686
+ data.flags = LMEMFLAG;
687
+ }
688
+
689
+ rv = dbh->db->pget(dbh->db,txn?txn->txn:NULL,&key,&pkey,&data,flags);
690
+ if ( rv == 0 ) {
691
+ return
692
+ rb_ary_new3(2,
693
+ rb_str_new(pkey.data,pkey.size),
694
+ rb_str_new(data.data,data.size));
695
+
696
+ } else if (rv == DB_NOTFOUND) {
697
+ return Qnil;
698
+ } else {
699
+ raise_error(rv, "db_pget failure: %s",db_strerror(rv));
700
+ }
701
+ return Qnil;
702
+ }
703
+
704
+ /*
705
+ * call-seq:
706
+ * db[key] -> data
707
+ *
708
+ * array ref style data retrieval
709
+ *
710
+ */
711
+ VALUE db_aget(VALUE obj, VALUE vkey)
712
+ {
713
+ return db_get(obj,Qnil,vkey,Qnil,Qnil);
714
+ }
715
+
716
+ /*
717
+ * call-seq:
718
+ * db[key]=data
719
+ *
720
+ * array ref style data storage
721
+ */
722
+ VALUE db_aset(VALUE obj, VALUE vkey, VALUE vdata)
723
+ {
724
+ return db_put(obj,Qnil,vkey,vdata,Qnil);
725
+ }
726
+
727
+ /*
728
+ * call-seq:
729
+ * db.join([cursors],flags) -> join_cursor
730
+ *
731
+ * create a join cursor from an array of cursors.
732
+ * The input cursors will usually be set_range and, if duplicate
733
+ * data items are allowed the should be DUP_SORT or the performance
734
+ * will be abysmal.
735
+ */
736
+ VALUE db_join(VALUE obj, VALUE vacurs, VALUE vflags)
737
+ {
738
+ t_dbh *dbh;
739
+ t_dbch *dbch;
740
+ u_int32_t flags;
741
+ DBC **curs;
742
+ int i,rv;
743
+ VALUE jcurs;
744
+
745
+ flags=NUM2UINT(vflags);
746
+ Data_Get_Struct(obj,t_dbh,dbh);
747
+ if (!dbh->db)
748
+ raise(0, "db is closed");
749
+
750
+ curs = ALLOCA_N(DBC *,RARRAY(vacurs)->len);
751
+ for (i=0; i<RARRAY(vacurs)->len; i++) {
752
+ Data_Get_Struct(RARRAY(vacurs)->ptr[i],t_dbch,dbch);
753
+ /* cursor is closed? */
754
+ curs[i]=dbch->dbc;
755
+ }
756
+ curs[i]=NULL;
757
+ jcurs=Data_Make_Struct(cCursor,t_dbch,dbc_mark,dbc_free,dbch);
758
+ rv = dbh->db->join(dbh->db,curs,&(dbch->dbc),flags);
759
+ if (rv) {
760
+ raise_error(rv, "db_join: %s",db_strerror(rv));
761
+ }
762
+ dbch->db=dbh;
763
+ rb_ary_push(dbch->db->adbc,jcurs);
764
+ rb_obj_call_init(jcurs,0,NULL);
765
+ return jcurs;
766
+ }
767
+
768
+ #if DB_VERSION_MINOR > 3
769
+ /*
770
+ * call-seq:
771
+ * db.compact(txn,start_key,stop_key,compact_opts,flags) -> end_key
772
+ *
773
+ * compact the database (4.4 an up). start and stop keys limit the
774
+ * range of compaction in BTREE types. compact_opts is currently
775
+ * ignored. Call returns the last key compacted (could be fed into
776
+ * a subsequent call as the start_key).
777
+ *
778
+ */
779
+ VALUE db_compact(VALUE obj, VALUE vtxn, VALUE vstart_key,
780
+ VALUE vstop_key, VALUE db_compact,
781
+ VALUE vflags)
782
+ {
783
+ t_dbh *dbh;
784
+ u_int32_t flags;
785
+ t_txnh *txn=NULL;
786
+ DBT start_key, stop_key, end_key;
787
+ int rv;
788
+
789
+ flags=NUM2UINT(vflags);
790
+ Data_Get_Struct(obj,t_dbh,dbh);
791
+ if (!dbh->db)
792
+ raise(0, "db is closed");
793
+
794
+ memset(&start_key,0,sizeof(DBT));
795
+ memset(&stop_key,0,sizeof(DBT));
796
+ memset(&end_key,0,sizeof(DBT));
797
+
798
+ if ( ! NIL_P(vstart_key) ) {
799
+ StringValue(vstart_key);
800
+ start_key.data=RSTRING_PTR(vstart_key);
801
+ start_key.size=RSTRING_LEN(vstart_key);
802
+ start_key.flags= LMEMFLAG;
803
+ }
804
+ if ( ! NIL_P(vstop_key) ) {
805
+ StringValue(vstop_key);
806
+ stop_key.data=RSTRING_PTR(vstop_key);
807
+ stop_key.size=RSTRING_LEN(vstop_key);
808
+ stop_key.flags= LMEMFLAG;
809
+ }
810
+ if ( ! NIL_P(vtxn) ) {
811
+ Data_Get_Struct(vtxn,t_txnh,txn);
812
+ if (!txn->txn)
813
+ raise(0, "txn is closed");
814
+ }
815
+
816
+ rv=dbh->db->compact(dbh->db,txn?txn->txn:NULL,
817
+ &start_key,
818
+ &stop_key,
819
+ NULL,
820
+ flags,
821
+ &end_key);
822
+ if (rv)
823
+ raise_error(rv,"db_compact failure: %s",db_strerror(rv));
824
+
825
+ return rb_str_new(end_key.data,end_key.size);
826
+
827
+ }
828
+ #endif
829
+
830
+ /*
831
+ * call-seq:
832
+ * db.get_byteswapped -> true/false
833
+ *
834
+ * true if database is running in swapped mode. This happens when
835
+ * the db is created on a machine with a different endian.
836
+ */
837
+ VALUE db_get_byteswapped(VALUE obj)
838
+ {
839
+ t_dbh *dbh;
840
+ int rv;
841
+ int is_swapped;
842
+
843
+ Data_Get_Struct(obj,t_dbh,dbh);
844
+ if (!dbh->db)
845
+ raise(0, "db is closed");
846
+ rv=dbh->db->get_byteswapped(dbh->db,&is_swapped);
847
+ if (rv)
848
+ raise_error(rv,"db_get_byteswapped failed: %s",db_strerror(rv));
849
+ if (is_swapped)
850
+ return Qtrue;
851
+ else
852
+ return Qfalse;
853
+ }
854
+
855
+ /*
856
+ * call-seq:
857
+ * db.get_type -> Fixnum(type)
858
+ *
859
+ * an integer indicating the type of db (BTREE, HASH, etc).
860
+ */
861
+ VALUE db_get_type(VALUE obj)
862
+ {
863
+ t_dbh *dbh;
864
+ int rv;
865
+ DBTYPE dbtype;
866
+
867
+ Data_Get_Struct(obj,t_dbh,dbh);
868
+ if (!dbh->db)
869
+ raise(0, "db is closed");
870
+ rv=dbh->db->get_type(dbh->db,&dbtype);
871
+ if (rv)
872
+ raise_error(rv,"db_get_type failed: %s",db_strerror(rv));
873
+ return INT2FIX(dbtype);
874
+ }
875
+
876
+ /*
877
+ * call-seq:
878
+ * db.remove(disk_file,logical_db,flags) -> true
879
+ *
880
+ * removes a whole database file, or just a logical_db within
881
+ * that file, i.e. if file and logical are both specified, only
882
+ * the logical will be removed. the Bdb::Db instance cannot have
883
+ * been previously used for anything and cannot be used after.
884
+ */
885
+ VALUE db_remove(VALUE obj, VALUE vdisk_file,
886
+ VALUE vlogical_db, VALUE vflags)
887
+ {
888
+ t_dbh *dbh;
889
+ int rv;
890
+ u_int32_t flags=0;
891
+ char *logical_db=NULL;
892
+
893
+ if ( ! NIL_P(vflags) )
894
+ flags=NUM2UINT(vflags);
895
+
896
+ Data_Get_Struct(obj,t_dbh,dbh);
897
+ if (!dbh->db)
898
+ raise(0, "db is closed");
899
+ rv=dbh->db->remove(dbh->db,
900
+ NIL_P(vdisk_file)?NULL:StringValueCStr(vdisk_file),
901
+ NIL_P(vlogical_db)?NULL:StringValueCStr(vlogical_db),
902
+ flags);
903
+ /* handle cannot be accessed again per docs */
904
+ dbh->db=NULL;
905
+ if (rv)
906
+ raise_error(rv,"db_remove failed: %s",db_strerror(rv));
907
+ return Qtrue;
908
+ }
909
+
910
+ /*
911
+ * call-seq:
912
+ * db.rename(file,logical,newname,flags) -> true
913
+ *
914
+ * rename a file or logical db to newname.
915
+ */
916
+ VALUE db_rename(VALUE obj, VALUE vdisk_file,
917
+ VALUE vlogical_db, VALUE newname, VALUE vflags)
918
+ {
919
+ t_dbh *dbh;
920
+ int rv;
921
+ u_int32_t flags=0;
922
+ char *disk_file=NULL;
923
+ char *logical_db=NULL;
924
+
925
+ if ( ! NIL_P(vflags) )
926
+ flags=NUM2UINT(vflags);
927
+
928
+ if ( NIL_P(newname) )
929
+ raise_error(0,"db_rename newname must be specified");
930
+
931
+ Data_Get_Struct(obj,t_dbh,dbh);
932
+ if (!dbh->db)
933
+ raise(0, "db is closed");
934
+ rv=dbh->db->rename(dbh->db,
935
+ NIL_P(vdisk_file)?NULL:StringValueCStr(vdisk_file),
936
+ NIL_P(vlogical_db)?NULL:StringValueCStr(vlogical_db),
937
+ StringValueCStr(newname),
938
+ flags);
939
+
940
+ if (rv) {
941
+ raise_error(rv,"db_rename failed: %s",db_strerror(rv));
942
+ }
943
+ return Qtrue;
944
+ }
945
+
946
+ /*
947
+ * call-seq:
948
+ * db.sync -> true
949
+ *
950
+ * sync the database out to storage.
951
+ */
952
+ VALUE db_sync(VALUE obj)
953
+ {
954
+ t_dbh *dbh;
955
+ int rv;
956
+
957
+ Data_Get_Struct(obj,t_dbh,dbh);
958
+ if (!dbh->db)
959
+ raise(0, "db is closed");
960
+ rv=dbh->db->sync(dbh->db,NOFLAGS);
961
+
962
+ if (rv)
963
+ raise_error(rv,"db_sync failed: %s",db_strerror(rv));
964
+ return Qtrue;
965
+ }
966
+
967
+ /*
968
+ * call-seq:
969
+ * db.truncate(txn) -> Fixnum(record_count)
970
+ *
971
+ * truncate, i.e. remove all records, purge, trash.
972
+ *
973
+ */
974
+ VALUE db_truncate(VALUE obj, VALUE vtxn)
975
+ {
976
+ t_dbh *dbh;
977
+ t_txnh *txn=NULL;
978
+ int rv;
979
+ VALUE result;
980
+ u_int32_t count;
981
+
982
+ if ( ! NIL_P(vtxn) ) {
983
+ Data_Get_Struct(vtxn,t_txnh,txn);
984
+ if (!txn->txn)
985
+ raise(0, "txn is closed");
986
+ }
987
+
988
+ Data_Get_Struct(obj,t_dbh,dbh);
989
+ if (!dbh->db)
990
+ raise(0, "db is closed");
991
+
992
+ rv=dbh->db->truncate(dbh->db,txn?txn->txn:NULL,&count,NOFLAGS);
993
+ if (rv)
994
+ raise_error(rv,"db_truncate: %s",db_strerror(rv));
995
+
996
+ return INT2FIX(count);
997
+ }
998
+
999
+ /*
1000
+ * call-seq:
1001
+ * db.key_range(txn,vkey,flags) -> [#less,#same,#greater]
1002
+ *
1003
+ * calculate position of key within database. returns the counts
1004
+ * of keys less, same and greater than the given key as an
1005
+ * array of Fixnum-s
1006
+ */
1007
+ VALUE db_key_range(VALUE obj, VALUE vtxn, VALUE vkey, VALUE vflags)
1008
+ {
1009
+ t_dbh *dbh;
1010
+ t_txnh *txn=NULL;
1011
+ DBT key;
1012
+ u_int32_t flags;
1013
+ int rv;
1014
+ DB_KEY_RANGE key_range;
1015
+ VALUE result;
1016
+
1017
+ if ( ! NIL_P(vtxn) ) {
1018
+ Data_Get_Struct(vtxn,t_txnh,txn);
1019
+ if (!txn->txn)
1020
+ raise(0, "txn is closed");
1021
+ }
1022
+
1023
+ if ( ! NIL_P(vflags) )
1024
+ flags=NUM2UINT(vflags);
1025
+
1026
+ Data_Get_Struct(obj,t_dbh,dbh);
1027
+ if (!dbh->db)
1028
+ raise(0, "db is closed");
1029
+
1030
+ memset(&key,0,sizeof(DBT));
1031
+ StringValue(vkey);
1032
+ key.data = RSTRING_PTR(vkey);
1033
+ key.size = RSTRING_LEN(vkey);
1034
+ key.flags = LMEMFLAG;
1035
+
1036
+ rv=dbh->db->key_range(dbh->db,txn?txn->txn:NULL,&key,
1037
+ &key_range,flags);
1038
+ if (rv)
1039
+ raise_error(rv,"db_key_range: %s",db_strerror(rv));
1040
+
1041
+ result=rb_ary_new3(3,
1042
+ rb_float_new(key_range.less),
1043
+ rb_float_new(key_range.equal),
1044
+ rb_float_new(key_range.greater));
1045
+ return result;
1046
+ }
1047
+
1048
+ /*
1049
+ * call-seq:
1050
+ * db.del(txn,key,flags) -> true/nil
1051
+ *
1052
+ * delete records with the key given. DUP values will removed
1053
+ * as a group. true if deleted extant records. NIL if the
1054
+ * operation resulted in DB indicating DB_NOTFOUND.
1055
+ *
1056
+ */
1057
+ VALUE db_del(VALUE obj, VALUE vtxn, VALUE vkey, VALUE vflags)
1058
+ {
1059
+ t_dbh *dbh;
1060
+ int rv;
1061
+ u_int32_t flags;
1062
+ DBT key;
1063
+ VALUE str;
1064
+ t_txnh *txn=NULL;
1065
+
1066
+ memset(&key,0,sizeof(DBT));
1067
+
1068
+ if ( ! NIL_P(vtxn) ) {
1069
+ Data_Get_Struct(vtxn,t_txnh,txn);
1070
+ if (!txn->txn)
1071
+ raise(0, "txn is closed");
1072
+ }
1073
+
1074
+ flags=NUM2UINT(vflags);
1075
+ Data_Get_Struct(obj,t_dbh,dbh);
1076
+ if (!dbh->db)
1077
+ raise(0, "db is closed");
1078
+
1079
+ StringValue(vkey);
1080
+ key.data = RSTRING_PTR(vkey);
1081
+ key.size = RSTRING_LEN(vkey);
1082
+ key.flags = LMEMFLAG;
1083
+
1084
+ rv = dbh->db->del(dbh->db,txn?txn->txn:NULL,&key,flags);
1085
+ if ( rv == DB_NOTFOUND ) {
1086
+ return Qnil;
1087
+ } else if (rv != 0) {
1088
+ raise_error(rv, "db_del failure: %s",db_strerror(rv));
1089
+ }
1090
+ return Qtrue;
1091
+ }
1092
+
1093
+ void assoc_key(DBT* result, VALUE obj) {
1094
+ VALUE str=StringValue(obj);
1095
+
1096
+ #ifdef DEBUG_DB
1097
+ fprintf(stderr,"assoc_key %*s", RSTRING_LEN(str),RSTRING_PTR(str));
1098
+ #endif
1099
+
1100
+ result->data=RSTRING_PTR(str);
1101
+ result->size=RSTRING_LEN(str);
1102
+ result->flags=LMEMFLAG;
1103
+ }
1104
+
1105
+ VALUE
1106
+ assoc_callback2(VALUE *args)
1107
+ {
1108
+ return rb_funcall(args[0],fv_call,3,args[1],args[2],args[3]);
1109
+ }
1110
+
1111
+ int assoc_callback(DB *secdb, const DBT* key, const DBT* data, DBT* result)
1112
+ {
1113
+ t_dbh *dbh;
1114
+ VALUE proc;
1115
+ int status;
1116
+ VALUE retv;
1117
+ VALUE args[4];
1118
+ VALUE keys;
1119
+ int i;
1120
+
1121
+ memset(result,0,sizeof(DBT));
1122
+ dbh=secdb->app_private;
1123
+
1124
+ args[0]=dbh->aproc;
1125
+ args[1]=dbh->self;
1126
+ args[2]=rb_str_new(key->data,key->size);
1127
+ args[3]=rb_str_new(data->data,data->size);
1128
+
1129
+ #ifdef DEBUG_DB
1130
+ fprintf(stderr,"assoc_data %*s", data->size, data->data);
1131
+ #endif
1132
+
1133
+ retv=rb_protect((VALUE(*)_((VALUE)))assoc_callback2,(VALUE)args,&status);
1134
+
1135
+ if (status) return 99999;
1136
+ if ( NIL_P(retv) )
1137
+ return DB_DONOTINDEX;
1138
+
1139
+ keys = rb_check_array_type(retv);
1140
+ if (!NIL_P(keys)) {
1141
+ keys = rb_funcall(keys,fv_uniq,0); /* secondary keys must be uniq */
1142
+ switch(RARRAY(keys)->len) {
1143
+ case 0:
1144
+ return DB_DONOTINDEX;
1145
+ case 1:
1146
+ retv=RARRAY(keys)->ptr[0];
1147
+ break;
1148
+ default:
1149
+ result->size=RARRAY(keys)->len;
1150
+ result->flags=DB_DBT_MULTIPLE | DB_DBT_APPMALLOC;
1151
+ result->data=malloc(result->size * sizeof(DBT));
1152
+ memset(result->data,0,result->size * sizeof(DBT));
1153
+
1154
+ for (i=0; i<result->size; i++) {
1155
+ assoc_key(result->data + i*sizeof(DBT), (VALUE)RARRAY(keys)->ptr[i]);
1156
+ }
1157
+ return 0;
1158
+ }
1159
+ }
1160
+
1161
+ assoc_key(result, retv);
1162
+ return 0;
1163
+ }
1164
+
1165
+ /*
1166
+ * call-seq:
1167
+ * db.associate(txn,sec_db,flags,proc)
1168
+ *
1169
+ * associate a secondary index(database) with this (primary)
1170
+ * database. The proc can be nil if the database is only opened
1171
+ * DB_RDONLY.
1172
+ *
1173
+ * call back proc has signature:
1174
+ * proc(secdb,key,value)
1175
+ */
1176
+ VALUE db_associate(VALUE obj, VALUE vtxn, VALUE osecdb,
1177
+ VALUE vflags, VALUE cb_proc)
1178
+ {
1179
+ t_dbh *sdbh,*pdbh;
1180
+ int rv;
1181
+ u_int32_t flags,flagsp,flagss;
1182
+ int fdp;
1183
+ t_txnh *txn=NOTXN;
1184
+
1185
+ flags=NUM2UINT(vflags);
1186
+ Data_Get_Struct(obj,t_dbh,pdbh);
1187
+ if (!pdbh->db)
1188
+ raise(0, "db is closed");
1189
+ Data_Get_Struct(osecdb,t_dbh,sdbh);
1190
+ if (!sdbh->db)
1191
+ raise(0, "sdb is closed");
1192
+
1193
+ if ( ! NIL_P(vtxn) ) {
1194
+ Data_Get_Struct(vtxn,t_txnh,txn);
1195
+ if (!txn->txn)
1196
+ raise(0, "txn is closed");
1197
+ }
1198
+
1199
+ if ( cb_proc == Qnil ) {
1200
+ rb_warning("db_associate: no association may be applied");
1201
+ pdbh->db->get_open_flags(pdbh->db,&flagsp);
1202
+ sdbh->db->get_open_flags(sdbh->db,&flagss);
1203
+ if ( flagsp & DB_RDONLY & flagss ) {
1204
+ rv=pdbh->db->associate(pdbh->db,txn?txn->txn:NULL,
1205
+ sdbh->db,NULL,flags);
1206
+ if (rv)
1207
+ raise_error(rv,"db_associate: %s",db_strerror(rv));
1208
+ return Qtrue;
1209
+ } else {
1210
+ raise_error(0,"db_associate empty associate only available when both DBs opened with DB_RDONLY");
1211
+ }
1212
+ } else if ( rb_obj_is_instance_of(cb_proc,rb_cProc) != Qtrue ) {
1213
+ raise_error(0, "db_associate proc required");
1214
+ }
1215
+
1216
+ sdbh->aproc=cb_proc;
1217
+
1218
+ rv=pdbh->db->associate(pdbh->db,txn?txn->txn:NULL,sdbh->db,assoc_callback,flags);
1219
+ #ifdef DEBUG_DB
1220
+ fprintf(stderr,"file is %d\n",fdp);
1221
+ fprintf(stderr,"assoc done 0x%x\n",sdbh);
1222
+ #endif
1223
+ if (rv != 0) {
1224
+ raise_error(rv, "db_associate failure: %s",db_strerror(rv));
1225
+ }
1226
+ return Qtrue;
1227
+ }
1228
+
1229
+ VALUE
1230
+ bt_compare_callback2(VALUE *args)
1231
+ {
1232
+ return rb_funcall(args[0],fv_call,3,args[1],args[2],args[3]);
1233
+ }
1234
+
1235
+ int bt_compare_callback(DB *db, const DBT* key1, const DBT* key2)
1236
+ {
1237
+ t_dbh *dbh;
1238
+ VALUE proc;
1239
+ int cmp;
1240
+ VALUE retv;
1241
+
1242
+ dbh=db->app_private;
1243
+
1244
+ /* Shouldn't catch exceptions in the callback, because bad sort data will corrupt the BTree.*/
1245
+ retv=rb_funcall(dbh->sproc,fv_call,3,dbh->self,
1246
+ rb_str_new(key1->data,key1->size),rb_str_new(key2->data,key2->size));
1247
+
1248
+ if (!FIXNUM_P(retv))
1249
+ rb_raise(rb_eTypeError,"btree comparison should return Fixnum");
1250
+
1251
+ cmp=FIX2INT(retv);
1252
+
1253
+ #ifdef DEBUG_DB
1254
+ fprintf(stderr,"bt_compare %*s <=> %*s: %d", key1->size, key1->data, key2->size, key2->data, cmp);
1255
+ #endif
1256
+
1257
+ return cmp;
1258
+ }
1259
+
1260
+ /*
1261
+ * call-seq:
1262
+ * db.btree_compare = proc
1263
+ *
1264
+ * set the btree key comparison function to the callback proc.
1265
+ *
1266
+ * callback proc has signature:
1267
+ * proc(db,key1,key2)
1268
+ */
1269
+ VALUE db_btree_compare_set(VALUE obj, VALUE cb_proc)
1270
+ {
1271
+ t_dbh *dbh;
1272
+ int rv;
1273
+
1274
+ Data_Get_Struct(obj,t_dbh,dbh);
1275
+ if (!dbh->db)
1276
+ raise(0, "db is closed");
1277
+
1278
+ if ( rb_obj_is_instance_of(cb_proc,rb_cProc) != Qtrue ) {
1279
+ raise_error(0, "db_associate proc required");
1280
+ }
1281
+
1282
+ dbh->sproc=cb_proc;
1283
+ rv=dbh->db->set_bt_compare(dbh->db,bt_compare_callback);
1284
+
1285
+ #ifdef DEBUG_DB
1286
+ fprintf(stderr,"btree_compare set 0x%x\n",dbh);
1287
+ #endif
1288
+ if (rv != 0) {
1289
+ raise_error(rv, "db_btree_compare_set failure: %s",db_strerror(rv));
1290
+ }
1291
+ return Qtrue;
1292
+ }
1293
+
1294
+ /*
1295
+ * call-seq:
1296
+ * db.cursor(txn,flags)
1297
+ *
1298
+ * open a cursor
1299
+ */
1300
+ VALUE db_cursor(VALUE obj, VALUE vtxn, VALUE vflags)
1301
+ {
1302
+ t_dbh *dbh;
1303
+ int rv;
1304
+ u_int32_t flags;
1305
+ DBC *dbc;
1306
+ t_txnh *txn=NOTXN;
1307
+ VALUE c_obj;
1308
+ t_dbch *dbch;
1309
+
1310
+ flags=NUM2UINT(vflags);
1311
+ Data_Get_Struct(obj,t_dbh,dbh);
1312
+ if (!dbh->db)
1313
+ raise(0, "db is closed");
1314
+
1315
+ c_obj=Data_Make_Struct(cCursor, t_dbch, dbc_mark, dbc_free, dbch);
1316
+
1317
+ if ( ! NIL_P(vtxn) ) {
1318
+ Data_Get_Struct(vtxn,t_txnh,txn);
1319
+ if (!txn->txn)
1320
+ raise(0, "txn is closed");
1321
+ }
1322
+
1323
+ rv=dbh->db->cursor(dbh->db,txn?txn->txn:NULL,&(dbch->dbc),flags);
1324
+ if (rv)
1325
+ raise_error(rv,"db_cursor: %s",db_strerror(rv));
1326
+
1327
+ filename_dup(dbch->filename,dbh->filename);
1328
+ dbch->db=dbh;
1329
+ rb_ary_push(dbch->db->adbc,c_obj);
1330
+ rb_obj_call_init(c_obj,0,NULL);
1331
+ return c_obj;
1332
+ }
1333
+
1334
+ /*
1335
+ * call-seq:
1336
+ * dbc.close -> nil
1337
+ *
1338
+ * close an open cursor
1339
+ */
1340
+ VALUE dbc_close(VALUE obj)
1341
+ {
1342
+ t_dbch *dbch;
1343
+ int rv;
1344
+ Data_Get_Struct(obj,t_dbch,dbch);
1345
+ if ( dbch->dbc ) {
1346
+ rv=dbch->dbc->c_close(dbch->dbc);
1347
+ rb_ary_delete(dbch->db->adbc,obj);
1348
+ dbch->db=NULL;
1349
+ dbch->dbc=NULL;
1350
+ if (rv)
1351
+ raise_error(rv,"dbc_close: %s",db_strerror(rv));
1352
+ }
1353
+ return Qnil;
1354
+ }
1355
+
1356
+ /*
1357
+ * call-seq:
1358
+ * dbc.get(key,data,flags) -> [key,data]
1359
+ *
1360
+ * get data by key or key and data. returns array of key,data
1361
+ */
1362
+ VALUE dbc_get(VALUE obj, VALUE vkey, VALUE vdata, VALUE vflags)
1363
+ {
1364
+ t_dbch *dbch;
1365
+ u_int32_t flags;
1366
+ DBT key,data;
1367
+ VALUE rar;
1368
+ int rv;
1369
+
1370
+ flags=NUM2UINT(vflags);
1371
+ Data_Get_Struct(obj,t_dbch,dbch);
1372
+ if (!dbch->dbc)
1373
+ raise(0, "dbc is closed");
1374
+
1375
+ memset(&key,0,sizeof(DBT));
1376
+ memset(&data,0,sizeof(DBT));
1377
+
1378
+ if ( ! NIL_P(vkey) ) {
1379
+ StringValue(vkey);
1380
+ key.data = RSTRING_PTR(vkey);
1381
+ key.size = RSTRING_LEN(vkey);
1382
+ key.flags = LMEMFLAG;
1383
+ }
1384
+ if ( ! NIL_P(vdata) ) {
1385
+ StringValue(vdata);
1386
+ data.data = RSTRING_PTR(vdata);
1387
+ data.size = RSTRING_LEN(vdata);
1388
+ data.flags = LMEMFLAG;
1389
+ }
1390
+
1391
+ rv = dbch->dbc->c_get(dbch->dbc,&key,&data,flags);
1392
+ if ( rv == 0 ) {
1393
+ rar = rb_ary_new3(2,rb_str_new(key.data,key.size),
1394
+ rb_str_new(data.data,data.size));
1395
+ return rar;
1396
+ } else if (rv == DB_NOTFOUND) {
1397
+ return Qnil;
1398
+ } else {
1399
+ raise_error(rv, "dbc_get %s",db_strerror(rv));
1400
+ }
1401
+ return Qnil;
1402
+ }
1403
+ /*
1404
+ * call-seq:
1405
+ * dbc.pget(key,data,flags) -> [key,pkey,data]
1406
+ *
1407
+ * cursor pget, returns array(key, primary key, data)
1408
+ */
1409
+ VALUE dbc_pget(VALUE obj, VALUE vkey, VALUE vdata, VALUE vflags)
1410
+ {
1411
+ t_dbch *dbch;
1412
+ u_int32_t flags;
1413
+ DBT key,data,pkey;
1414
+ VALUE rar;
1415
+ int rv;
1416
+
1417
+ flags=NUM2UINT(vflags);
1418
+ Data_Get_Struct(obj,t_dbch,dbch);
1419
+ if (!dbch->dbc)
1420
+ raise(0, "dbc is closed");
1421
+
1422
+ memset(&key,0,sizeof(DBT));
1423
+ memset(&data,0,sizeof(DBT));
1424
+ memset(&pkey,0,sizeof(DBT));
1425
+
1426
+ if ( ! NIL_P(vkey) ) {
1427
+ StringValue(vkey);
1428
+ key.data = RSTRING_PTR(vkey);
1429
+ key.size = RSTRING_LEN(vkey);
1430
+ key.flags = LMEMFLAG;
1431
+ }
1432
+ if ( ! NIL_P(vdata) ) {
1433
+ StringValue(vdata);
1434
+ data.data = RSTRING_PTR(vdata);
1435
+ data.size = RSTRING_LEN(vdata);
1436
+ data.flags = LMEMFLAG;
1437
+ }
1438
+
1439
+ rv = dbch->dbc->c_pget(dbch->dbc,&key,&pkey,&data,flags);
1440
+ if ( rv == 0 ) {
1441
+ rar = rb_ary_new3(3,
1442
+ rb_str_new(key.data,key.size),
1443
+ rb_str_new(pkey.data,pkey.size),
1444
+ rb_str_new(data.data,data.size));
1445
+ return rar;
1446
+ } else if (rv == DB_NOTFOUND) {
1447
+ return Qnil;
1448
+ } else {
1449
+ raise_error(rv, "dbc_pget %s",db_strerror(rv));
1450
+ }
1451
+ return Qnil;
1452
+ }
1453
+
1454
+ /*
1455
+ * call-seq:
1456
+ * dbc.put(key,data,flags) -> data
1457
+ *
1458
+ * cursor put key/data
1459
+ */
1460
+ VALUE dbc_put(VALUE obj, VALUE vkey, VALUE vdata, VALUE vflags)
1461
+ {
1462
+ t_dbch *dbch;
1463
+ u_int32_t flags;
1464
+ DBT key,data;
1465
+ int rv;
1466
+
1467
+ if ( NIL_P(vdata) )
1468
+ raise_error(0,"data element is required for put");
1469
+
1470
+ flags=NUM2UINT(vflags);
1471
+ Data_Get_Struct(obj,t_dbch,dbch);
1472
+ if (!dbch->dbc)
1473
+ raise(0, "dbc is closed");
1474
+
1475
+ memset(&key,0,sizeof(DBT));
1476
+ memset(&data,0,sizeof(DBT));
1477
+
1478
+ if ( ! NIL_P(vkey) ) {
1479
+ StringValue(vkey);
1480
+ key.data = RSTRING_PTR(vkey);
1481
+ key.size = RSTRING_LEN(vkey);
1482
+ key.flags = LMEMFLAG;
1483
+ }
1484
+
1485
+ StringValue(vdata);
1486
+ data.data = RSTRING_PTR(vdata);
1487
+ data.size = RSTRING_LEN(vdata);
1488
+ data.flags = LMEMFLAG;
1489
+
1490
+ rv = dbch->dbc->c_put(dbch->dbc,&key,&data,flags);
1491
+ if (rv != 0)
1492
+ raise_error(rv,"dbc_put failure: %s",db_strerror(rv));
1493
+
1494
+ return vdata;
1495
+ }
1496
+
1497
+ /*
1498
+ * call-seq:
1499
+ * dbc.del -> true|nil
1500
+ *
1501
+ * delete tuple at current cursor position. returns true if
1502
+ * something was deleted, nil otherwise (DB_KEYEMPTY)
1503
+ *
1504
+ */
1505
+ VALUE dbc_del(VALUE obj)
1506
+ {
1507
+ t_dbch *dbch;
1508
+ int rv;
1509
+
1510
+ Data_Get_Struct(obj,t_dbch,dbch);
1511
+ if (!dbch->dbc)
1512
+ raise(0, "dbc is closed");
1513
+ rv = dbch->dbc->c_del(dbch->dbc,NOFLAGS);
1514
+ if (rv == DB_KEYEMPTY)
1515
+ return Qnil;
1516
+ else if (rv != 0) {
1517
+ raise_error(rv, "dbc_del failure: %s",db_strerror(rv));
1518
+ }
1519
+ return Qtrue;
1520
+ }
1521
+
1522
+ /*
1523
+ * call-seq:
1524
+ * dbc.count -> Fixnum(count)
1525
+ *
1526
+ * returns cursor count as per DB.
1527
+ */
1528
+ VALUE dbc_count(VALUE obj)
1529
+ {
1530
+ t_dbch *dbch;
1531
+ int rv;
1532
+ db_recno_t count;
1533
+
1534
+ Data_Get_Struct(obj,t_dbch,dbch);
1535
+ if (!dbch->dbc)
1536
+ raise(0, "dbc is closed");
1537
+ rv = dbch->dbc->c_count(dbch->dbc,&count,NOFLAGS);
1538
+ if (rv != 0)
1539
+ raise_error(rv, "db_count failure: %s",db_strerror(rv));
1540
+
1541
+ return INT2FIX(count);
1542
+ }
1543
+
1544
+ static void env_free(void *p)
1545
+ {
1546
+ t_envh *eh;
1547
+ eh=(t_envh *)p;
1548
+
1549
+ #ifdef DEBUG_DB
1550
+ if ( RTEST(ruby_debug) )
1551
+ fprintf(stderr,"%s/%d %s 0x%x\n",__FILE__,__LINE__,"env_free cleanup!",p);
1552
+ #endif
1553
+
1554
+ if ( eh ) {
1555
+ if ( eh->env ) {
1556
+ eh->env->close(eh->env,NOFLAGS);
1557
+ eh->env=NULL;
1558
+ }
1559
+ free(p);
1560
+ }
1561
+ }
1562
+ static void env_mark(t_envh *eh)
1563
+ {
1564
+ rb_gc_mark(eh->adb);
1565
+ rb_gc_mark(eh->atxn);
1566
+ }
1567
+
1568
+ /*
1569
+ * Document-class: Bdb::Env
1570
+ *
1571
+ * Encapsulated DB environment. Create by simple new (with
1572
+ * flags as neede), then open. Database handles created with
1573
+ * env.db -> Bdb::Db object.
1574
+ */
1575
+
1576
+ /*
1577
+ * call-seq:
1578
+ * new(flags) -> object
1579
+ *
1580
+ *
1581
+ */
1582
+ VALUE env_new(VALUE class, VALUE vflags)
1583
+ {
1584
+ t_envh *eh;
1585
+ int rv;
1586
+ u_int32_t flags=0;
1587
+ VALUE obj;
1588
+
1589
+ if ( ! NIL_P(vflags) )
1590
+ flags=NUM2UINT(vflags);
1591
+
1592
+ obj=Data_Make_Struct(class,t_envh,env_mark,env_free,eh);
1593
+ rv=db_env_create(&(eh->env),flags);
1594
+ if ( rv != 0 ) {
1595
+ raise_error(rv,"env_new: %s",db_strerror(rv));
1596
+ return Qnil;
1597
+ }
1598
+ eh->self=obj;
1599
+ eh->adb = rb_ary_new();
1600
+ eh->atxn = rb_ary_new();
1601
+ rb_obj_call_init(obj,0,NULL);
1602
+ return obj;
1603
+ }
1604
+
1605
+ /*
1606
+ * call-seq:
1607
+ * env.open(homedir,flags,mode) -> self
1608
+ *
1609
+ * open an environment
1610
+ */
1611
+ VALUE env_open(VALUE obj, VALUE vhome, VALUE vflags, VALUE vmode)
1612
+ {
1613
+ t_envh *eh;
1614
+ int rv;
1615
+ u_int32_t flags=0;
1616
+ int mode=0;
1617
+
1618
+ if ( ! NIL_P(vflags) )
1619
+ flags=NUM2UINT(vflags);
1620
+ if ( ! NIL_P(vmode) )
1621
+ mode=NUM2INT(vmode);
1622
+ Data_Get_Struct(obj,t_envh,eh);
1623
+ if (!eh->env)
1624
+ raise(0, "env is closed");
1625
+ if ( NIL_P(eh->adb) )
1626
+ raise_error(0,"env handle already used and closed");
1627
+
1628
+ rv = eh->env->open(eh->env,StringValueCStr(vhome),flags,mode);
1629
+ if (rv != 0) {
1630
+ raise_error(rv, "env_open failure: %s",db_strerror(rv));
1631
+ }
1632
+ return obj;
1633
+ }
1634
+
1635
+ VALUE txn_abort(VALUE);
1636
+
1637
+ /*
1638
+ * call-seq:
1639
+ * env.close -> self
1640
+ *
1641
+ * close an environment. Do not use it after you close it.
1642
+ * The close process will automatically abort any open transactions
1643
+ * and close open databases (which also closes open cursors).
1644
+ * But this is just an effort to keep your dbs and envs from
1645
+ * becoming corrupted due to ruby errors that exit
1646
+ * unintentionally. However, to make this at all worth anything
1647
+ * use ObjectSpace.define_finalizer which calls env.close to
1648
+ * approach some assurance of it happening.
1649
+ *
1650
+ */
1651
+ VALUE env_close(VALUE obj)
1652
+ {
1653
+ t_envh *eh;
1654
+ VALUE db;
1655
+ int rv;
1656
+
1657
+ Data_Get_Struct(obj,t_envh,eh);
1658
+ if ( eh->env==NULL )
1659
+ return Qnil;
1660
+
1661
+ if (RARRAY(eh->adb)->len > 0) {
1662
+ rb_warning("%s/%d %s %d",__FILE__,__LINE__,
1663
+ "database handles still open",RARRAY(eh->adb)->len);
1664
+ while (RARRAY(eh->adb)->len > 0)
1665
+ if ((db=rb_ary_pop(eh->adb)) != Qnil ) {
1666
+ rb_warning("%s/%d %s 0x%x",__FILE__,__LINE__,
1667
+ "closing",db);
1668
+ /* this could raise! needs rb_protect */
1669
+ db_close(db,INT2FIX(0));
1670
+ }
1671
+ }
1672
+ if (RARRAY(eh->atxn)->len > 0) {
1673
+ rb_warning("%s/%d %s",__FILE__,__LINE__,
1674
+ "database transactions still open");
1675
+ while ( (db=rb_ary_pop(eh->atxn)) != Qnil ) {
1676
+ /* this could raise! needs rb_protect */
1677
+ txn_abort(db);
1678
+ }
1679
+ }
1680
+
1681
+ if ( RTEST(ruby_debug) )
1682
+ rb_warning("%s/%d %s 0x%x",__FILE__,__LINE__,"env_close!",eh);
1683
+
1684
+ rv = eh->env->close(eh->env,NOFLAGS);
1685
+ eh->env=NULL;
1686
+ eh->adb=Qnil;
1687
+ eh->atxn=Qnil;
1688
+ if ( rv != 0 ) {
1689
+ raise_error(rv, "env_close failure: %s",db_strerror(rv));
1690
+ return Qnil;
1691
+ }
1692
+ return obj;
1693
+ }
1694
+
1695
+ /*
1696
+ * call-seq:
1697
+ * env.db -> Bdb::Db instance
1698
+ *
1699
+ * create a db associated with an environment
1700
+ */
1701
+ VALUE env_db(VALUE obj)
1702
+ {
1703
+ t_envh *eh;
1704
+ VALUE dbo;
1705
+
1706
+ Data_Get_Struct(obj,t_envh,eh);
1707
+ if (!eh->env)
1708
+ raise(0, "env is closed");
1709
+ dbo = Data_Wrap_Struct(cDb,db_mark,db_free,0);
1710
+
1711
+ return db_init_aux(dbo,eh);
1712
+ }
1713
+
1714
+ /*
1715
+ * call-seq:
1716
+ * env.cachesize=Fixnum|Bignum
1717
+ *
1718
+ * set the environment cache size. If it is a Bignum then it
1719
+ * will populate the bytes and gbytes part of the DB struct.
1720
+ * Fixnums will only populate bytes (which is still pretty big).
1721
+ */
1722
+ VALUE env_set_cachesize(VALUE obj, VALUE size)
1723
+ {
1724
+ t_envh *eh;
1725
+ unsigned long long ln;
1726
+ u_int32_t bytes=0,gbytes=0;
1727
+ int rv;
1728
+ Data_Get_Struct(obj,t_envh,eh);
1729
+ if (!eh->env)
1730
+ raise(0, "env is closed");
1731
+
1732
+ if ( TYPE(size) == T_BIGNUM ) {
1733
+ ln = rb_big2ull(size);
1734
+ gbytes = ln / (1024*1024*1024);
1735
+ bytes = ln - (gbytes*1024*1024*1024);
1736
+ } else if (FIXNUM_P(size) ) {
1737
+ bytes=NUM2UINT(size);
1738
+ } else {
1739
+ raise_error(0,"set_cachesize requires number");
1740
+ return Qnil;
1741
+ }
1742
+
1743
+ rv=eh->env->set_cachesize(eh->env,gbytes,bytes,1);
1744
+ if ( rv != 0 ) {
1745
+ raise_error(rv, "set_cachesize failure: %s",db_strerror(rv));
1746
+ return Qnil;
1747
+ }
1748
+
1749
+ return Qtrue;
1750
+ }
1751
+
1752
+ /*
1753
+ * call-seq:
1754
+ * env.cachesize -> Fixnum|Bignum
1755
+ *
1756
+ * return the environment cache size. If it is a Bignum then it
1757
+ * will populate the bytes and gbytes part of the DB struct.
1758
+ * Fixnums will only populate bytes (which is still pretty big).
1759
+ */
1760
+ VALUE env_get_cachesize(VALUE obj)
1761
+ {
1762
+ t_envh *eh;
1763
+ unsigned long long ln;
1764
+ u_int32_t bytes=0,gbytes=0;
1765
+ int ncache;
1766
+ int rv;
1767
+ Data_Get_Struct(obj,t_envh,eh);
1768
+ if (!eh->env)
1769
+ raise(0, "env is closed");
1770
+
1771
+ rv=eh->env->get_cachesize(eh->env,&gbytes,&bytes,&ncache);
1772
+ if ( rv != 0 ) {
1773
+ raise_error(rv, "get_cachesize failure: %s",db_strerror(rv));
1774
+ return Qnil;
1775
+ }
1776
+
1777
+ if (gbytes != 0)
1778
+ return ULL2NUM(gbytes*1024*1024*1024+bytes);
1779
+ else
1780
+ return UINT2NUM(bytes);
1781
+
1782
+ return Qtrue;
1783
+ }
1784
+
1785
+ VALUE env_set_flags(VALUE obj, VALUE vflags, int onoff)
1786
+ {
1787
+ t_envh *eh;
1788
+ int rv;
1789
+ u_int32_t flags;
1790
+
1791
+ Data_Get_Struct(obj,t_envh,eh);
1792
+ if (!eh->env)
1793
+ raise(0, "env is closed");
1794
+ if ( ! NIL_P(vflags) ) {
1795
+ flags=NUM2UINT(vflags);
1796
+
1797
+ rv=eh->env->set_flags(eh->env,flags,onoff);
1798
+
1799
+ if ( rv != 0 ) {
1800
+ raise_error(rv, "set_flags failure: %s",db_strerror(rv));
1801
+ return Qnil;
1802
+ }
1803
+ }
1804
+ return Qtrue;
1805
+ }
1806
+
1807
+ /*
1808
+ * call-seq:
1809
+ * env.flags -> flags
1810
+ *
1811
+ * get what flags are on.
1812
+ */
1813
+ VALUE env_get_flags(VALUE obj)
1814
+ {
1815
+ t_envh *eh;
1816
+ int rv;
1817
+ u_int32_t flags;
1818
+
1819
+ Data_Get_Struct(obj,t_envh,eh);
1820
+ if (!eh->env)
1821
+ raise(0, "env is closed");
1822
+
1823
+ rv=eh->env->get_flags(eh->env,&flags);
1824
+
1825
+ if ( rv != 0 ) {
1826
+ raise_error(rv, "set_flags failure: %s",db_strerror(rv));
1827
+ return Qnil;
1828
+ }
1829
+
1830
+ return UINT2NUM(flags);
1831
+ }
1832
+
1833
+ /*
1834
+ * call-seq:
1835
+ * env.flags_on=flags
1836
+ *
1837
+ * set the 'flags' on. An or'ed set of flags will be set on.
1838
+ * Only included flags will be affected. Serialized calls
1839
+ * will only affect flags indicated (leaving others, default or
1840
+ * set as they were).
1841
+ */
1842
+ VALUE env_set_flags_on(VALUE obj, VALUE vflags)
1843
+ {
1844
+ return env_set_flags(obj,vflags,1);
1845
+ }
1846
+
1847
+ /*
1848
+ * call-seq:
1849
+ * env.flags_off=flags
1850
+ *
1851
+ * set the 'flags' off. An or'ed set of flags will be set off.
1852
+ * Only included flags will be affected. Serialized calls
1853
+ * will only affect flags indicated (leaving others, default or
1854
+ * set as they were).
1855
+ */
1856
+ VALUE env_set_flags_off(VALUE obj, VALUE vflags)
1857
+ {
1858
+ return env_set_flags(obj,vflags,0);
1859
+ }
1860
+
1861
+ /*
1862
+ * call-seq:
1863
+ * env.list_dbs -> [Bdb::Db array]
1864
+ *
1865
+ * return 0 or more open databases within the receiver environment.
1866
+ * If 0, will return [], not nil.
1867
+ */
1868
+ VALUE env_list_dbs(VALUE obj)
1869
+ {
1870
+ t_envh *eh;
1871
+ Data_Get_Struct(obj,t_envh,eh);
1872
+ if (!eh->env)
1873
+ raise(0, "env is closed");
1874
+ return eh->adb;
1875
+ }
1876
+ static void txn_mark(t_txnh *txn)
1877
+ {
1878
+ if (txn->env)
1879
+ rb_gc_mark(txn->env->self);
1880
+ }
1881
+ static void txn_free(t_txnh *txn)
1882
+ {
1883
+ #ifdef DEBUG_DB
1884
+ if ( RTEST(ruby_debug) )
1885
+ fprintf(stderr,"%s/%d %s %p\n",__FILE__,__LINE__,"txn_free",txn);
1886
+ #endif
1887
+
1888
+ if (txn) {
1889
+ if (txn->txn)
1890
+ txn->txn->abort(txn->txn);
1891
+ txn->txn=NULL;
1892
+ if (txn->env) {
1893
+ rb_ary_delete(txn->env->atxn,txn->self);
1894
+ }
1895
+ txn->env=NULL;
1896
+
1897
+ free(txn);
1898
+ }
1899
+ }
1900
+
1901
+ /*
1902
+ * call-seq:
1903
+ * env.txn_begin(txn_parent,flags) -> Bdb::Txn
1904
+ *
1905
+ * start a root transaction or embedded (via txn_parent).
1906
+ */
1907
+ VALUE env_txn_begin(VALUE obj, VALUE vtxn_parent, VALUE vflags)
1908
+ {
1909
+ t_txnh *parent=NULL, *txn=NULL;
1910
+ u_int32_t flags=0;
1911
+ int rv;
1912
+ t_envh *eh;
1913
+ VALUE t_obj;
1914
+
1915
+ if ( ! NIL_P(vflags))
1916
+ flags=NUM2UINT(vflags);
1917
+ if ( ! NIL_P(vtxn_parent) ) {
1918
+ Data_Get_Struct(vtxn_parent,t_txnh,parent);
1919
+ if (!parent->txn)
1920
+ raise(0, "parent txn is closed");
1921
+ }
1922
+
1923
+ Data_Get_Struct(obj,t_envh,eh);
1924
+ if (!eh->env)
1925
+ raise(0, "env is closed");
1926
+ t_obj=Data_Make_Struct(cTxn,t_txnh,txn_mark,txn_free,txn);
1927
+
1928
+ rv=eh->env->txn_begin(eh->env,parent?parent->txn:NULL,
1929
+ &(txn->txn),flags);
1930
+
1931
+ if ( rv != 0 ) {
1932
+ raise_error(rv, "env_txn_begin: %s",db_strerror(rv));
1933
+ return Qnil;
1934
+ }
1935
+ txn->env=eh;
1936
+ txn->self=t_obj;
1937
+ rb_ary_push(eh->atxn,t_obj);
1938
+
1939
+ /* Once we get this working, we'll have to track transactions */
1940
+ rb_obj_call_init(t_obj,0,NULL);
1941
+ return t_obj;
1942
+ }
1943
+
1944
+ /*
1945
+ * call-seq:
1946
+ * env.txn_checkpoint -> true
1947
+ *
1948
+ * Cause env transaction state to be checkpointed.
1949
+ */
1950
+ VALUE env_txn_checkpoint(VALUE obj, VALUE vkbyte, VALUE vmin,
1951
+ VALUE vflags)
1952
+ {
1953
+ u_int32_t flags=0;
1954
+ int rv;
1955
+ t_envh *eh;
1956
+ u_int32_t kbyte=0, min=0;
1957
+
1958
+ if ( ! NIL_P(vflags))
1959
+ flags=NUM2UINT(vflags);
1960
+
1961
+ if ( FIXNUM_P(vkbyte) )
1962
+ kbyte=FIX2UINT(vkbyte);
1963
+
1964
+ if ( FIXNUM_P(vmin) )
1965
+ min=FIX2UINT(vmin);
1966
+
1967
+ Data_Get_Struct(obj,t_envh,eh);
1968
+ if (!eh->env)
1969
+ raise(0, "env is closed");
1970
+ rv=eh->env->txn_checkpoint(eh->env,kbyte,min,flags);
1971
+ if ( rv != 0 ) {
1972
+ raise_error(rv, "env_txn_checkpoint: %s",db_strerror(rv));
1973
+ return Qnil;
1974
+ }
1975
+ return Qtrue;
1976
+ }
1977
+
1978
+ VALUE env_txn_stat_active(DB_TXN_ACTIVE *t)
1979
+ {
1980
+ VALUE ao;
1981
+
1982
+ ao=rb_class_new_instance(0,NULL,cTxnStatActive);
1983
+
1984
+ rb_iv_set(ao,"@txnid",INT2FIX(t->txnid));
1985
+ rb_iv_set(ao,"@parentid",INT2FIX(t->parentid));
1986
+ /* rb_iv_set(ao,"@thread_id",INT2FIX(t->thread_id)); */
1987
+ rb_iv_set(ao,"@lsn",rb_ary_new3(2,
1988
+ INT2FIX(t->lsn.file),
1989
+ INT2FIX(t->lsn.offset)));
1990
+ /* XA status is currently excluded */
1991
+ return ao;
1992
+ }
1993
+
1994
+ /*
1995
+ * call-seq:
1996
+ * db.stat(txn,flags) -> Bdb::Db::Stat
1997
+ *
1998
+ * get database status. Returns a Bdb::Db::Stat object that
1999
+ * is specialized to the db_type and only responds to [] to
2000
+ * retrieve status values. All values are stored in instance
2001
+ * variables, so singleton classes can be created and instance_eval
2002
+ * will work.
2003
+ */
2004
+ VALUE db_stat(VALUE obj, VALUE vtxn, VALUE vflags)
2005
+ {
2006
+ u_int32_t flags=0;
2007
+ int rv;
2008
+ t_dbh *dbh;
2009
+ t_txnh *txn=NULL;
2010
+ DBTYPE dbtype;
2011
+ union {
2012
+ void *stat;
2013
+ DB_HASH_STAT *hstat;
2014
+ DB_BTREE_STAT *bstat;
2015
+ DB_QUEUE_STAT *qstat;
2016
+ } su;
2017
+ VALUE s_obj;
2018
+
2019
+ if ( ! NIL_P(vflags) )
2020
+ flags=NUM2UINT(vflags);
2021
+ if ( ! NIL_P(vtxn) ) {
2022
+ Data_Get_Struct(vtxn,t_txnh,txn);
2023
+ if (!txn->txn)
2024
+ raise(0, "txn is closed");
2025
+ }
2026
+
2027
+ Data_Get_Struct(obj,t_dbh,dbh);
2028
+ if (!dbh->db)
2029
+ raise(0, "db is closed");
2030
+
2031
+ rv=dbh->db->get_type(dbh->db,&dbtype);
2032
+ if (rv)
2033
+ raise_error(rv,"db_stat %s",db_strerror(rv));
2034
+ #if DB_VERSION_MINOR > 2
2035
+ rv=dbh->db->stat(dbh->db,txn?txn->txn:NULL,&(su.stat),flags);
2036
+ #else
2037
+ rv=dbh->db->stat(dbh->db,&(su.stat),flags);
2038
+ #endif
2039
+ if (rv)
2040
+ raise_error(rv,"db_stat %s",db_strerror(rv));
2041
+
2042
+ s_obj=rb_class_new_instance(0,NULL,cDbStat);
2043
+ rb_iv_set(s_obj,"@dbtype",INT2FIX(dbtype));
2044
+
2045
+ switch(dbtype) {
2046
+
2047
+ #define hs_int(field) \
2048
+ rb_iv_set(s_obj,"@" #field,INT2FIX(su.hstat->field))
2049
+
2050
+ case DB_HASH:
2051
+ hs_int(hash_magic);
2052
+ hs_int(hash_version); /* Version number. */
2053
+ hs_int(hash_metaflags); /* Metadata flags. */
2054
+ hs_int(hash_nkeys); /* Number of unique keys. */
2055
+ hs_int(hash_ndata); /* Number of data items. */
2056
+ hs_int(hash_pagesize); /* Page size. */
2057
+ hs_int(hash_ffactor); /* Fill factor specified at create. */
2058
+ hs_int(hash_buckets); /* Number of hash buckets. */
2059
+ hs_int(hash_free); /* Pages on the free list. */
2060
+ hs_int(hash_bfree); /* Bytes free on bucket pages. */
2061
+ hs_int(hash_bigpages); /* Number of big key/data pages. */
2062
+ hs_int(hash_big_bfree); /* Bytes free on big item pages. */
2063
+ hs_int(hash_overflows); /* Number of overflow pages. */
2064
+ hs_int(hash_ovfl_free); /* Bytes free on ovfl pages. */
2065
+ hs_int(hash_dup); /* Number of dup pages. */
2066
+ hs_int(hash_dup_free); /* Bytes free on duplicate pages. */
2067
+ break;
2068
+
2069
+ #define bs_int(field) \
2070
+ rb_iv_set(s_obj,"@" #field,INT2FIX(su.bstat->field))
2071
+
2072
+ case DB_BTREE:
2073
+ case DB_RECNO:
2074
+ bs_int(bt_magic); /* Magic number. */
2075
+ bs_int(bt_version); /* Version number. */
2076
+ bs_int(bt_metaflags); /* Metadata flags. */
2077
+ bs_int(bt_nkeys); /* Number of unique keys. */
2078
+ bs_int(bt_ndata); /* Number of data items. */
2079
+ bs_int(bt_pagesize); /* Page size. */
2080
+ #if DB_VERSION_MINOR < 4
2081
+ bs_int(bt_maxkey); /* Maxkey value. */
2082
+ #endif
2083
+ bs_int(bt_minkey); /* Minkey value. */
2084
+ bs_int(bt_re_len); /* Fixed-length record length. */
2085
+ bs_int(bt_re_pad); /* Fixed-length record pad. */
2086
+ bs_int(bt_levels); /* Tree levels. */
2087
+ bs_int(bt_int_pg); /* Internal pages. */
2088
+ bs_int(bt_leaf_pg); /* Leaf pages. */
2089
+ bs_int(bt_dup_pg); /* Duplicate pages. */
2090
+ bs_int(bt_over_pg); /* Overflow pages. */
2091
+ #if DB_VERSION_MINOR > 2
2092
+ bs_int(bt_empty_pg); /* Empty pages. */
2093
+ #endif
2094
+ bs_int(bt_free); /* Pages on the free list. */
2095
+ bs_int(bt_int_pgfree); /* Bytes free in internal pages. */
2096
+ bs_int(bt_leaf_pgfree); /* Bytes free in leaf pages. */
2097
+ bs_int(bt_dup_pgfree); /* Bytes free in duplicate pages. */
2098
+ bs_int(bt_over_pgfree); /* Bytes free in overflow pages. */
2099
+
2100
+ break;
2101
+
2102
+ #define qs_int(field) \
2103
+ rb_iv_set(s_obj,"@" #field,INT2FIX(su.qstat->field))
2104
+
2105
+ case DB_QUEUE:
2106
+ qs_int(qs_magic); /* Magic number. */
2107
+ qs_int(qs_version); /* Version number. */
2108
+ qs_int(qs_metaflags); /* Metadata flags. */
2109
+ qs_int(qs_nkeys); /* Number of unique keys. */
2110
+ qs_int(qs_ndata); /* Number of data items. */
2111
+ qs_int(qs_pagesize); /* Page size. */
2112
+ qs_int(qs_extentsize); /* Pages per extent. */
2113
+ qs_int(qs_pages); /* Data pages. */
2114
+ qs_int(qs_re_len); /* Fixed-length record length. */
2115
+ qs_int(qs_re_pad); /* Fixed-length record pad. */
2116
+ qs_int(qs_pgfree); /* Bytes free in data pages. */
2117
+ qs_int(qs_first_recno); /* First not deleted record. */
2118
+ qs_int(qs_cur_recno); /* Next available record number. */
2119
+
2120
+ break;
2121
+ }
2122
+
2123
+ free(su.stat);
2124
+ return s_obj;
2125
+ }
2126
+
2127
+ /*
2128
+ * call-seq:
2129
+ * stat[name] -> value
2130
+ *
2131
+ * return status value
2132
+ */
2133
+ VALUE stat_aref(VALUE obj, VALUE vname)
2134
+ {
2135
+ rb_iv_get(obj,RSTRING_PTR(rb_str_concat(rb_str_new2("@"),vname)));
2136
+ }
2137
+
2138
+ /*
2139
+ * call-seq:
2140
+ * env.txn_stat -> Bdb::TxnStat
2141
+ *
2142
+ * get the environment transaction status. Each active
2143
+ * transaction will be contained within a Bdb::TxnStat::Active
2144
+ * class.
2145
+ */
2146
+ VALUE env_txn_stat(VALUE obj, VALUE vflags)
2147
+ {
2148
+ u_int32_t flags=0;
2149
+ int rv;
2150
+ t_envh *eh;
2151
+ DB_TXN_STAT *statp;
2152
+ VALUE s_obj;
2153
+ VALUE active;
2154
+ int i;
2155
+
2156
+ if ( ! NIL_P(vflags))
2157
+ flags=NUM2UINT(vflags);
2158
+
2159
+ Data_Get_Struct(obj,t_envh,eh);
2160
+ if (!eh->env)
2161
+ raise(0, "env is closed");
2162
+
2163
+ /* statp will need free() */
2164
+ rv=eh->env->txn_stat(eh->env,&statp,flags);
2165
+ if ( rv != 0 ) {
2166
+ raise_error(rv, "txn_stat: %s",db_strerror(rv));
2167
+ }
2168
+
2169
+ s_obj=rb_class_new_instance(0,NULL,cTxnStat);
2170
+ rb_iv_set(s_obj,"@st_last_ckp",
2171
+ rb_ary_new3(2,
2172
+ INT2FIX(statp->st_last_ckp.file),
2173
+ INT2FIX(statp->st_last_ckp.offset)) );
2174
+ rb_iv_set(s_obj,"@st_time_ckp",
2175
+ rb_time_new(statp->st_time_ckp,0));
2176
+ rb_iv_set(s_obj,"@st_last_txnid",
2177
+ INT2FIX(statp->st_last_txnid));
2178
+ rb_iv_set(s_obj,"@st_maxtxns",
2179
+ INT2FIX(statp->st_maxtxns));
2180
+ rb_iv_set(s_obj,"@st_nactive",
2181
+ INT2FIX(statp->st_nactive));
2182
+ rb_iv_set(s_obj,"@st_maxnactive",
2183
+ INT2FIX(statp->st_maxnactive));
2184
+ rb_iv_set(s_obj,"@st_nbegins",
2185
+ INT2FIX(statp->st_nbegins));
2186
+ rb_iv_set(s_obj,"@st_naborts",
2187
+ INT2FIX(statp->st_naborts));
2188
+ rb_iv_set(s_obj,"@st_ncommits",
2189
+ INT2FIX(statp->st_ncommits));
2190
+ rb_iv_set(s_obj,"@st_nrestores",
2191
+ INT2FIX(statp->st_nrestores));
2192
+ rb_iv_set(s_obj,"@st_regsize",
2193
+ INT2FIX(statp->st_regsize));
2194
+ rb_iv_set(s_obj,"@st_region_wait",
2195
+ INT2FIX(statp->st_region_wait));
2196
+ rb_iv_set(s_obj,"@st_region_nowait",
2197
+ INT2FIX(statp->st_region_nowait));
2198
+ rb_iv_set(s_obj,"@st_txnarray",
2199
+ active=rb_ary_new2(statp->st_nactive));
2200
+
2201
+ for (i=0; i<statp->st_nactive; i++) {
2202
+ rb_ary_push(active,env_txn_stat_active(&(statp->st_txnarray[i])));
2203
+ }
2204
+
2205
+ free(statp);
2206
+ return s_obj;
2207
+ }
2208
+
2209
+ /*
2210
+ * call-seq:
2211
+ * env.set_timeout(timeout,flags) -> timeout
2212
+ *
2213
+ * set lock and transaction timeout
2214
+ */
2215
+ VALUE env_set_timeout(VALUE obj, VALUE vtimeout, VALUE vflags)
2216
+ {
2217
+ t_envh *eh;
2218
+ u_int32_t flags=0;
2219
+ db_timeout_t timeout;
2220
+ int rv;
2221
+
2222
+ if ( ! NIL_P(vflags))
2223
+ flags=NUM2UINT(vflags);
2224
+ timeout=FIX2UINT(vtimeout);
2225
+
2226
+ Data_Get_Struct(obj,t_envh,eh);
2227
+ if (!eh->env)
2228
+ raise(0, "env is closed");
2229
+ rv=eh->env->set_timeout(eh->env,timeout,flags);
2230
+ if ( rv != 0 ) {
2231
+ raise_error(rv, "env_set_timeout: %s",db_strerror(rv));
2232
+ }
2233
+
2234
+ return vtimeout;
2235
+ }
2236
+
2237
+ /*
2238
+ * call-seq:
2239
+ * env.get_timeout(flags) -> Fixnum
2240
+ *
2241
+ * Get current transaction and lock timeout value
2242
+ */
2243
+ VALUE env_get_timeout(VALUE obj, VALUE vflags)
2244
+ {
2245
+ t_envh *eh;
2246
+ u_int32_t flags=0;
2247
+ db_timeout_t timeout;
2248
+ int rv;
2249
+
2250
+ if ( ! NIL_P(vflags))
2251
+ flags=NUM2UINT(vflags);
2252
+
2253
+ Data_Get_Struct(obj,t_envh,eh);
2254
+ if (!eh->env)
2255
+ raise(0, "env is closed");
2256
+ rv=eh->env->get_timeout(eh->env,&timeout,flags);
2257
+ if ( rv != 0 ) {
2258
+ raise_error(rv, "env_get_timeout: %s",db_strerror(rv));
2259
+ }
2260
+
2261
+ return INT2FIX(timeout);
2262
+ }
2263
+
2264
+ /*
2265
+ * call-seq:
2266
+ * env.set_tx_max(max) -> max
2267
+ *
2268
+ * Set the maximum number of transactions with the environment
2269
+ */
2270
+ VALUE env_set_tx_max(VALUE obj, VALUE vmax)
2271
+ {
2272
+ t_envh *eh;
2273
+ u_int32_t max;
2274
+ int rv;
2275
+
2276
+ max=FIX2UINT(vmax);
2277
+
2278
+ Data_Get_Struct(obj,t_envh,eh);
2279
+ if (!eh->env)
2280
+ raise(0, "env is closed");
2281
+ rv=eh->env->set_tx_max(eh->env,max);
2282
+ if ( rv != 0 ) {
2283
+ raise_error(rv, "env_set_tx_max: %s",db_strerror(rv));
2284
+ }
2285
+
2286
+ return vmax;
2287
+ }
2288
+
2289
+ /*
2290
+ * call-seq
2291
+ * env.get_tx_max -> Fixnum
2292
+ *
2293
+ * Get current maximum number of transactions
2294
+ */
2295
+ VALUE env_get_tx_max(VALUE obj)
2296
+ {
2297
+ t_envh *eh;
2298
+ u_int32_t max;
2299
+ int rv;
2300
+
2301
+ Data_Get_Struct(obj,t_envh,eh);
2302
+ if (!eh->env)
2303
+ raise(0, "env is closed");
2304
+ rv=eh->env->get_tx_max(eh->env,&max);
2305
+ if ( rv != 0 ) {
2306
+ raise_error(rv, "env_get_tx_max: %s",db_strerror(rv));
2307
+ }
2308
+
2309
+ return INT2FIX(max);
2310
+ }
2311
+
2312
+ /*
2313
+ * call-seq:
2314
+ * env.set_shm_key(key) -> max
2315
+ *
2316
+ * Set the shared memory key base
2317
+ */
2318
+ VALUE env_set_shm_key(VALUE obj, VALUE vkey)
2319
+ {
2320
+ t_envh *eh;
2321
+ long key;
2322
+ int rv;
2323
+
2324
+ key=FIX2UINT(vkey);
2325
+
2326
+ Data_Get_Struct(obj,t_envh,eh);
2327
+ if (!eh->env)
2328
+ raise(0, "env is closed");
2329
+ rv=eh->env->set_shm_key(eh->env,key);
2330
+ if ( rv != 0 ) {
2331
+ raise_error(rv, "env_set_shm_key: %s",db_strerror(rv));
2332
+ }
2333
+
2334
+ return vkey;
2335
+ }
2336
+
2337
+ /*
2338
+ * call-seq
2339
+ * env.get_shm_key -> Fixnum
2340
+ *
2341
+ * Get the current shm key base
2342
+ */
2343
+ VALUE env_get_shm_key(VALUE obj)
2344
+ {
2345
+ t_envh *eh;
2346
+ long key;
2347
+ int rv;
2348
+
2349
+ Data_Get_Struct(obj,t_envh,eh);
2350
+ if (!eh->env)
2351
+ raise(0, "env is closed");
2352
+ rv=eh->env->get_shm_key(eh->env,&key);
2353
+ if ( rv != 0 ) {
2354
+ raise_error(rv, "env_get_shm_key: %s",db_strerror(rv));
2355
+ }
2356
+
2357
+ return INT2FIX(key);
2358
+ }
2359
+
2360
+ /*
2361
+ * call-seq:
2362
+ * env.set_lk_detect(detect) -> detect
2363
+ *
2364
+ * Set when lock detector should be run
2365
+ */
2366
+ VALUE env_set_lk_detect(VALUE obj, VALUE vdetect)
2367
+ {
2368
+ t_envh *eh;
2369
+ u_int32_t detect;
2370
+ int rv;
2371
+
2372
+ detect=NUM2UINT(vdetect);
2373
+
2374
+ Data_Get_Struct(obj,t_envh,eh);
2375
+ if (!eh->env)
2376
+ raise(0, "env is closed");
2377
+ rv=eh->env->set_lk_detect(eh->env,detect);
2378
+ if ( rv != 0 ) {
2379
+ raise_error(rv, "env_set_lk_detect: %s",db_strerror(rv));
2380
+ }
2381
+
2382
+ return vdetect;
2383
+ }
2384
+
2385
+ /*
2386
+ * call-seq:
2387
+ * env.get_lk_detect() -> detect
2388
+ *
2389
+ * Get when lock detector should be run
2390
+ */
2391
+ VALUE env_get_lk_detect(VALUE obj)
2392
+ {
2393
+ t_envh *eh;
2394
+ u_int32_t detect;
2395
+ int rv;
2396
+
2397
+ Data_Get_Struct(obj,t_envh,eh);
2398
+ if (!eh->env)
2399
+ raise(0, "env is closed");
2400
+ rv=eh->env->get_lk_detect(eh->env,&detect);
2401
+ if ( rv != 0 ) {
2402
+ raise_error(rv, "env_set_lk_detect: %s",db_strerror(rv));
2403
+ }
2404
+
2405
+ return UINT2NUM(detect);
2406
+ }
2407
+
2408
+ /*
2409
+ * call-seq:
2410
+ * env.set_lk_max_locks(max) -> max
2411
+ *
2412
+ * Set the maximum number of locks in the environment
2413
+ */
2414
+ VALUE env_set_lk_max_locks(VALUE obj, VALUE vmax)
2415
+ {
2416
+ t_envh *eh;
2417
+ u_int32_t max;
2418
+ int rv;
2419
+
2420
+ max=FIX2UINT(vmax);
2421
+
2422
+ Data_Get_Struct(obj,t_envh,eh);
2423
+ if (!eh->env)
2424
+ raise(0, "env is closed");
2425
+ rv=eh->env->set_lk_max_locks(eh->env,max);
2426
+ if ( rv != 0 ) {
2427
+ raise_error(rv, "env_set_lk_max_locks: %s",db_strerror(rv));
2428
+ }
2429
+
2430
+ return vmax;
2431
+ }
2432
+
2433
+ /*
2434
+ * call-seq:
2435
+ * env.get_lk_max_locks -> max
2436
+ *
2437
+ * Get the maximum number of locks in the environment
2438
+ */
2439
+ VALUE env_get_lk_max_locks(VALUE obj)
2440
+ {
2441
+ t_envh *eh;
2442
+ u_int32_t max;
2443
+ int rv;
2444
+
2445
+ Data_Get_Struct(obj,t_envh,eh);
2446
+ if (!eh->env)
2447
+ raise(0, "env is closed");
2448
+ rv=eh->env->get_lk_max_locks(eh->env,&max);
2449
+ if ( rv != 0 ) {
2450
+ raise_error(rv, "env_get_lk_max_locks: %s",db_strerror(rv));
2451
+ }
2452
+
2453
+ return UINT2NUM(max);
2454
+ }
2455
+
2456
+ /*
2457
+ * call-seq:
2458
+ * env.set_lk_max_objects(max) -> max
2459
+ *
2460
+ * Set the maximum number of locks in the environment
2461
+ */
2462
+ VALUE env_set_lk_max_objects(VALUE obj, VALUE vmax)
2463
+ {
2464
+ t_envh *eh;
2465
+ u_int32_t max;
2466
+ int rv;
2467
+
2468
+ max=FIX2UINT(vmax);
2469
+
2470
+ Data_Get_Struct(obj,t_envh,eh);
2471
+ if (!eh->env)
2472
+ raise(0, "env is closed");
2473
+ rv=eh->env->set_lk_max_objects(eh->env,max);
2474
+ if ( rv != 0 ) {
2475
+ raise_error(rv, "env_set_lk_max_objects: %s",db_strerror(rv));
2476
+ }
2477
+
2478
+ return vmax;
2479
+ }
2480
+
2481
+ /*
2482
+ * call-seq:
2483
+ * env.get_lk_max_objects -> max
2484
+ *
2485
+ * Get the maximum number of locks in the environment
2486
+ */
2487
+ VALUE env_get_lk_max_objects(VALUE obj)
2488
+ {
2489
+ t_envh *eh;
2490
+ u_int32_t max;
2491
+ int rv;
2492
+
2493
+ Data_Get_Struct(obj,t_envh,eh);
2494
+ if (!eh->env)
2495
+ raise(0, "env is closed");
2496
+ rv=eh->env->get_lk_max_objects(eh->env,&max);
2497
+ if ( rv != 0 ) {
2498
+ raise_error(rv, "env_get_lk_max_objects: %s",db_strerror(rv));
2499
+ }
2500
+
2501
+ return UINT2NUM(max);
2502
+ }
2503
+
2504
+ VALUE env_report_stderr(VALUE obj)
2505
+ {
2506
+ t_envh *eh;
2507
+ u_int32_t max;
2508
+ int rv;
2509
+
2510
+ Data_Get_Struct(obj,t_envh,eh);
2511
+ if (!eh->env)
2512
+ raise(0, "env is closed");
2513
+ eh->env->set_errfile(eh->env,stderr);
2514
+
2515
+ return Qtrue;
2516
+ }
2517
+
2518
+ /*
2519
+ * call-seq:
2520
+ * env.set_data_dir(data_dir) -> data_dir
2521
+ *
2522
+ * set data_dir
2523
+ */
2524
+ VALUE env_set_data_dir(VALUE obj, VALUE vdata_dir)
2525
+ {
2526
+ t_envh *eh;
2527
+ const char *data_dir;
2528
+ int rv;
2529
+
2530
+ data_dir=StringValueCStr(vdata_dir);
2531
+
2532
+ Data_Get_Struct(obj,t_envh,eh);
2533
+ if (!eh->env)
2534
+ raise(0, "env is closed");
2535
+ rv=eh->env->set_data_dir(eh->env,data_dir);
2536
+ if ( rv != 0 ) {
2537
+ raise_error(rv, "env_set_data_dir: %s",db_strerror(rv));
2538
+ }
2539
+
2540
+ return vdata_dir;
2541
+ }
2542
+
2543
+ /*
2544
+ * call-seq:
2545
+ * env.get_data_dir -> [data_dir_1, data_dir_2, ...]
2546
+ *
2547
+ * get data_dir
2548
+ */
2549
+ VALUE env_get_data_dirs(VALUE obj)
2550
+ {
2551
+ t_envh *eh;
2552
+ const char **data_dirs;
2553
+ int rv;
2554
+ int ln;
2555
+
2556
+ Data_Get_Struct(obj,t_envh,eh);
2557
+ if (!eh->env)
2558
+ raise(0, "env is closed");
2559
+ rv=eh->env->get_data_dirs(eh->env,&data_dirs);
2560
+ if ( rv != 0 ) {
2561
+ raise_error(rv, "env_get_data_dir: %s",db_strerror(rv));
2562
+ }
2563
+
2564
+ ln = (sizeof (data_dirs))/sizeof(data_dirs[0]);
2565
+ VALUE rb_data_dirs = rb_ary_new2(ln);
2566
+ int i;
2567
+ for (i=0; i<ln; i++) {
2568
+ rb_ary_push(rb_data_dirs, rb_str_new2(data_dirs[i]));
2569
+ }
2570
+
2571
+ return rb_data_dirs;
2572
+ }
2573
+
2574
+ /*
2575
+ * call-seq:
2576
+ * env.set_lg_dir(lg_dir) -> lg_dir
2577
+ *
2578
+ * set lg_dir
2579
+ */
2580
+ VALUE env_set_lg_dir(VALUE obj, VALUE vlg_dir)
2581
+ {
2582
+ t_envh *eh;
2583
+ const char *lg_dir;
2584
+ int rv;
2585
+
2586
+ lg_dir=StringValueCStr(vlg_dir);
2587
+
2588
+ Data_Get_Struct(obj,t_envh,eh);
2589
+ if (!eh->env)
2590
+ raise(0, "env is closed");
2591
+ rv=eh->env->set_lg_dir(eh->env,lg_dir);
2592
+ if ( rv != 0 ) {
2593
+ raise_error(rv, "env_set_lg_dir: %s",db_strerror(rv));
2594
+ }
2595
+
2596
+ return vlg_dir;
2597
+ }
2598
+
2599
+ /*
2600
+ * call-seq:
2601
+ * env.get_lg_dir -> lg_dir
2602
+ *
2603
+ * get lg_dir
2604
+ */
2605
+ VALUE env_get_lg_dir(VALUE obj)
2606
+ {
2607
+ t_envh *eh;
2608
+ const char *lg_dir;
2609
+ int rv;
2610
+
2611
+ Data_Get_Struct(obj,t_envh,eh);
2612
+ if (!eh->env)
2613
+ raise(0, "env is closed");
2614
+ rv=eh->env->get_lg_dir(eh->env,&lg_dir);
2615
+ if ( rv != 0 ) {
2616
+ raise_error(rv, "env_get_lg_dir: %s",db_strerror(rv));
2617
+ }
2618
+
2619
+ return rb_str_new2(lg_dir);
2620
+ }
2621
+
2622
+ /*
2623
+ * call-seq:
2624
+ * env.set_tmp_dir(tmp_dir) -> tmp_dir
2625
+ *
2626
+ * set tmp_dir
2627
+ */
2628
+ VALUE env_set_tmp_dir(VALUE obj, VALUE vtmp_dir)
2629
+ {
2630
+ t_envh *eh;
2631
+ const char *tmp_dir;
2632
+ int rv;
2633
+
2634
+ tmp_dir=StringValueCStr(vtmp_dir);
2635
+
2636
+ Data_Get_Struct(obj,t_envh,eh);
2637
+ if (!eh->env)
2638
+ raise(0, "env is closed");
2639
+ rv=eh->env->set_tmp_dir(eh->env,tmp_dir);
2640
+ if ( rv != 0 ) {
2641
+ raise_error(rv, "env_set_tmp_dir: %s",db_strerror(rv));
2642
+ }
2643
+
2644
+ return vtmp_dir;
2645
+ }
2646
+
2647
+ /*
2648
+ * call-seq:
2649
+ * env.get_tmp_dir -> tmp_dir
2650
+ *
2651
+ * get tmp_dir
2652
+ */
2653
+ VALUE env_get_tmp_dir(VALUE obj)
2654
+ {
2655
+ t_envh *eh;
2656
+ const char *tmp_dir;
2657
+ int rv;
2658
+
2659
+ Data_Get_Struct(obj,t_envh,eh);
2660
+ if (!eh->env)
2661
+ raise(0, "env is closed");
2662
+ rv=eh->env->get_tmp_dir(eh->env,&tmp_dir);
2663
+ if ( rv != 0 ) {
2664
+ raise_error(rv, "env_get_tmp_dir: %s",db_strerror(rv));
2665
+ }
2666
+
2667
+ return rb_str_new2(tmp_dir);
2668
+ }
2669
+
2670
+ /*
2671
+ * call-seq:
2672
+ * env.get_home -> home
2673
+ *
2674
+ * get home
2675
+ */
2676
+ VALUE env_get_home(VALUE obj)
2677
+ {
2678
+ t_envh *eh;
2679
+ const char *home;
2680
+ int rv;
2681
+
2682
+ Data_Get_Struct(obj,t_envh,eh);
2683
+ if (!eh->env)
2684
+ raise(0, "env is closed");
2685
+ rv=eh->env->get_home(eh->env,&home);
2686
+ if ( rv != 0 ) {
2687
+ raise_error(rv, "env_get_home: %s",db_strerror(rv));
2688
+ }
2689
+
2690
+ return rb_str_new2(home);
2691
+ }
2692
+
2693
+ static void txn_finish(t_txnh *txn)
2694
+ {
2695
+ if ( RTEST(ruby_debug) )
2696
+ rb_warning("%s/%d %s 0x%x",__FILE__,__LINE__,"txn_finish",txn);
2697
+
2698
+ txn->txn=NULL;
2699
+ if (txn->env) {
2700
+ rb_ary_delete(txn->env->atxn,txn->self);
2701
+ txn->env=NULL;
2702
+ }
2703
+ }
2704
+
2705
+ /*
2706
+ * call-seq:
2707
+ * txn.commit(flags) -> true
2708
+ *
2709
+ * commit a transaction
2710
+ */
2711
+ VALUE txn_commit(VALUE obj, VALUE vflags)
2712
+ {
2713
+ t_txnh *txn=NULL;
2714
+ u_int32_t flags=0;
2715
+ int rv;
2716
+
2717
+ if ( ! NIL_P(vflags))
2718
+ flags=NUM2UINT(vflags);
2719
+
2720
+ Data_Get_Struct(obj,t_txnh,txn);
2721
+
2722
+ if (!txn->txn)
2723
+ return Qfalse;
2724
+
2725
+ rv=txn->txn->commit(txn->txn,flags);
2726
+ txn_finish(txn);
2727
+ if ( rv != 0 ) {
2728
+ raise_error(rv, "txn_commit: %s",db_strerror(rv));
2729
+ return Qnil;
2730
+ }
2731
+ return Qtrue;
2732
+ }
2733
+
2734
+ /*
2735
+ * call-seq:
2736
+ * txn.abort -> true
2737
+ *
2738
+ * abort a transaction
2739
+ */
2740
+ VALUE txn_abort(VALUE obj)
2741
+ {
2742
+ t_txnh *txn=NULL;
2743
+ int rv;
2744
+
2745
+ Data_Get_Struct(obj,t_txnh,txn);
2746
+
2747
+ if (!txn->txn)
2748
+ return Qfalse;
2749
+
2750
+ rv=txn->txn->abort(txn->txn);
2751
+ txn_finish(txn);
2752
+ if ( rv != 0 ) {
2753
+ raise_error(rv, "txn_abort: %s",db_strerror(rv));
2754
+ return Qnil;
2755
+ }
2756
+ return Qtrue;
2757
+ }
2758
+
2759
+ /*
2760
+ * call-seq:
2761
+ * txn.discard -> true
2762
+ *
2763
+ * discard a transaction. Since prepare is not yet supported,
2764
+ * I don't think this has much value.
2765
+ */
2766
+ VALUE txn_discard(VALUE obj)
2767
+ {
2768
+ t_txnh *txn=NULL;
2769
+ int rv;
2770
+
2771
+ Data_Get_Struct(obj,t_txnh,txn);
2772
+
2773
+ if (!txn->txn)
2774
+ raise_error(0,"txn is closed");
2775
+
2776
+ rv=txn->txn->discard(txn->txn,NOFLAGS);
2777
+ txn_finish(txn);
2778
+ if ( rv != 0 ) {
2779
+ raise_error(rv, "txn_abort: %s",db_strerror(rv));
2780
+ return Qnil;
2781
+ }
2782
+ return Qtrue;
2783
+ }
2784
+
2785
+ /*
2786
+ * call-seq:
2787
+ * txn.tid -> Fixnum
2788
+ *
2789
+ * return the transaction id, (named tid to not conflict with
2790
+ * ruby's id method)
2791
+ */
2792
+ VALUE txn_id(VALUE obj)
2793
+ {
2794
+ t_txnh *txn=NULL;
2795
+ int rv;
2796
+
2797
+ Data_Get_Struct(obj,t_txnh,txn);
2798
+ if (!txn->txn)
2799
+ raise_error(0,"txn is closed");
2800
+
2801
+ rv=txn->txn->id(txn->txn);
2802
+ return INT2FIX(rv);
2803
+ }
2804
+
2805
+ /*
2806
+ * call-seq:
2807
+ * tx.set_timeout(timeout,flags) -> true
2808
+ *
2809
+ * set transaction lock timeout
2810
+ */
2811
+ VALUE txn_set_timeout(VALUE obj, VALUE vtimeout, VALUE vflags)
2812
+ {
2813
+ t_txnh *txn=NULL;
2814
+ db_timeout_t timeout;
2815
+ u_int32_t flags=0;
2816
+ int rv;
2817
+
2818
+ if ( ! NIL_P(vflags))
2819
+ flags=NUM2UINT(vflags);
2820
+
2821
+ if ( ! FIXNUM_P(vtimeout) )
2822
+ raise_error(0,"timeout must be a fixed integer");
2823
+ timeout=FIX2UINT(vtimeout);
2824
+
2825
+ Data_Get_Struct(obj,t_txnh,txn);
2826
+
2827
+ if (!txn->txn)
2828
+ raise_error(0,"txn is closed");
2829
+
2830
+ rv=txn->txn->set_timeout(txn->txn,timeout,flags);
2831
+ if ( rv != 0 ) {
2832
+ raise_error(rv, "txn_set_timeout: %s",db_strerror(rv));
2833
+ return Qnil;
2834
+ }
2835
+ return Qtrue;
2836
+ }
2837
+
2838
+ /*
2839
+ * Document-class: Bdb
2840
+ *
2841
+ * Ruby library that wraps the Sleepycat Berkeley DB.
2842
+ *
2843
+ * Developed against 4.3/4.4. No support for prior versions.
2844
+ */
2845
+
2846
+ void Init_bdb() {
2847
+ fv_call=rb_intern("call");
2848
+ fv_uniq=rb_intern("uniq");
2849
+ fv_err_new=rb_intern("new");
2850
+ fv_err_code=rb_intern("@code");
2851
+ fv_err_msg=rb_intern("@message");
2852
+
2853
+ mBdb = rb_define_module("Bdb");
2854
+
2855
+ #include "bdb_aux._c"
2856
+
2857
+ cDb = rb_define_class_under(mBdb,"Db", rb_cObject);
2858
+ eDbError = rb_define_class_under(mBdb,"DbError",rb_eStandardError);
2859
+ rb_define_method(eDbError,"initialize",err_initialize,2);
2860
+ rb_define_method(eDbError,"code",err_code,0);
2861
+
2862
+ rb_define_const(cDb,"BTREE",INT2FIX((DBTYPE)(DB_BTREE)));
2863
+ rb_define_const(cDb,"HASH",INT2FIX((DBTYPE)(DB_HASH)));
2864
+ rb_define_const(cDb,"RECNO",INT2FIX((DBTYPE)(DB_RECNO)));
2865
+ rb_define_const(cDb,"QUEUE",INT2FIX((DBTYPE)(DB_QUEUE)));
2866
+ rb_define_const(cDb,"UNKNOWN",INT2FIX((DBTYPE)(DB_UNKNOWN)));
2867
+
2868
+ rb_define_alloc_func(cDb,db_alloc);
2869
+ rb_define_method(cDb,"initialize",db_initialize,0);
2870
+
2871
+ rb_define_method(cDb,"put",db_put,4);
2872
+ rb_define_method(cDb,"get",db_get,4);
2873
+ rb_define_method(cDb,"pget",db_pget,4);
2874
+ rb_define_method(cDb,"del",db_del,3);
2875
+ rb_define_method(cDb,"cursor",db_cursor,2);
2876
+ rb_define_method(cDb,"associate",db_associate,4);
2877
+ rb_define_method(cDb,"btree_compare=",db_btree_compare_set,1);
2878
+ rb_define_method(cDb,"flags=",db_flags_set,1);
2879
+ rb_define_method(cDb,"flags",db_flags_get,0);
2880
+ rb_define_method(cDb,"open",db_open,6);
2881
+ rb_define_method(cDb,"close",db_close,1);
2882
+ rb_define_method(cDb,"[]",db_aget,1);
2883
+ rb_define_method(cDb,"[]=",db_aset,2);
2884
+ rb_define_method(cDb,"join",db_join,2);
2885
+ rb_define_method(cDb,"get_byteswapped",db_get_byteswapped,0);
2886
+ rb_define_method(cDb,"get_type",db_get_type,0);
2887
+ rb_define_method(cDb,"remove",db_remove,3);
2888
+ rb_define_method(cDb,"key_range",db_key_range,3);
2889
+ rb_define_method(cDb,"rename",db_rename,4);
2890
+ rb_define_method(cDb,"pagesize",db_pagesize,0);
2891
+ rb_define_method(cDb,"pagesize=",db_pagesize_set,1);
2892
+ rb_define_method(cDb,"h_ffactor",db_h_ffactor,0);
2893
+ rb_define_method(cDb,"h_ffactor=",db_h_ffactor_set,1);
2894
+ rb_define_method(cDb,"h_nelem",db_h_nelem,0);
2895
+ rb_define_method(cDb,"h_nelem=",db_h_nelem_set,1);
2896
+ rb_define_method(cDb,"stat",db_stat,2);
2897
+ cDbStat = rb_define_class_under(cDb,"Stat",rb_cObject);
2898
+ rb_define_method(cDbStat,"[]",stat_aref,1);
2899
+
2900
+ rb_define_method(cDb,"sync",db_sync,0);
2901
+ rb_define_method(cDb,"truncate",db_truncate,1);
2902
+
2903
+ #if DB_VERSION_MINOR > 3
2904
+ rb_define_method(cDb,"compact",db_compact,5);
2905
+ #endif
2906
+
2907
+ cCursor = rb_define_class_under(cDb,"Cursor",rb_cObject);
2908
+ rb_define_method(cCursor,"get",dbc_get,3);
2909
+ rb_define_method(cCursor,"pget",dbc_pget,3);
2910
+ rb_define_method(cCursor,"put",dbc_put,3);
2911
+ rb_define_method(cCursor,"close",dbc_close,0);
2912
+ rb_define_method(cCursor,"del",dbc_del,0);
2913
+ rb_define_method(cCursor,"count",dbc_count,0);
2914
+
2915
+ cEnv = rb_define_class_under(mBdb,"Env",rb_cObject);
2916
+ rb_define_singleton_method(cEnv,"new",env_new,1);
2917
+ rb_define_method(cEnv,"open",env_open,3);
2918
+ rb_define_method(cEnv,"close",env_close,0);
2919
+ rb_define_method(cEnv,"db",env_db,0);
2920
+ rb_define_method(cEnv,"cachesize=",env_set_cachesize,1);
2921
+ rb_define_method(cEnv,"cachesize",env_get_cachesize,0);
2922
+ rb_define_method(cEnv,"flags",env_get_flags,0);
2923
+ rb_define_method(cEnv,"flags_on=",env_set_flags_on,1);
2924
+ rb_define_method(cEnv,"flags_off=",env_set_flags_off,1);
2925
+ rb_define_method(cEnv,"list_dbs",env_list_dbs,0);
2926
+ rb_define_method(cEnv,"txn_begin",env_txn_begin,2);
2927
+ rb_define_method(cEnv,"txn_checkpoint",env_txn_checkpoint,3);
2928
+ rb_define_method(cEnv,"txn_stat",env_txn_stat,1);
2929
+ rb_define_method(cEnv,"set_timeout",env_set_timeout,2);
2930
+ rb_define_method(cEnv,"get_timeout",env_get_timeout,1);
2931
+ rb_define_method(cEnv,"set_tx_max",env_set_tx_max,1);
2932
+ rb_define_method(cEnv,"get_tx_max",env_get_tx_max,0);
2933
+ rb_define_method(cEnv,"report_stderr",env_report_stderr,0);
2934
+ rb_define_method(cEnv,"set_lk_detect",env_set_lk_detect,1);
2935
+ rb_define_method(cEnv,"get_lk_detect",env_get_lk_detect,0);
2936
+ rb_define_method(cEnv,"set_lk_max_locks",env_set_lk_max_locks,1);
2937
+ rb_define_method(cEnv,"get_lk_max_locks",env_get_lk_max_locks,0);
2938
+ rb_define_method(cEnv,"set_lk_max_objects",env_set_lk_max_objects,1);
2939
+ rb_define_method(cEnv,"get_lk_max_objects",env_get_lk_max_objects,0);
2940
+ rb_define_method(cEnv,"set_shm_key",env_set_shm_key,1);
2941
+ rb_define_method(cEnv,"get_shm_key",env_get_shm_key,0);
2942
+
2943
+ rb_define_method(cEnv,"set_data_dir",env_set_data_dir,1);
2944
+ rb_define_method(cEnv,"get_data_dirs",env_get_data_dirs,0);
2945
+ rb_define_method(cEnv,"set_lg_dir",env_set_lg_dir,1);
2946
+ rb_define_method(cEnv,"get_lg_dir",env_get_lg_dir,0);
2947
+ rb_define_method(cEnv,"set_tmp_dir",env_set_tmp_dir,1);
2948
+ rb_define_method(cEnv,"get_tmp_dir",env_get_tmp_dir,0);
2949
+ rb_define_method(cEnv,"get_home",env_get_home,0);
2950
+
2951
+ cTxnStat = rb_define_class_under(mBdb,"TxnStat",rb_cObject);
2952
+ rb_define_method(cTxnStat,"[]",stat_aref,1);
2953
+
2954
+ cTxnStatActive =
2955
+ rb_define_class_under(cTxnStat,"Active",rb_cObject);
2956
+ rb_define_method(cTxnStatActive,"[]",stat_aref,1);
2957
+
2958
+ cTxn = rb_define_class_under(mBdb,"Txn",rb_cObject);
2959
+ rb_define_method(cTxn,"commit",txn_commit,1);
2960
+ rb_define_method(cTxn,"abort",txn_abort,0);
2961
+ rb_define_method(cTxn,"discard",txn_discard,0);
2962
+ rb_define_method(cTxn,"tid",txn_id,0);
2963
+ rb_define_method(cTxn,"set_timeout",txn_set_timeout,2);
2964
+ }