bdb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Dan Janowski <danj@3skel.com>, Matt Bauer <bauer@pedalbrain.com>
2
+ Copyright (c) 2009 Justin Balthrop <code@justinbalthrop.com>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the "Software"), to deal in
6
+ the Software without restriction, including without limitation the rights to
7
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8
+ of the Software, and to permit persons to whom the Software is furnished to do
9
+ so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
@@ -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/ninjudd/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/ninjudd/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.8):
27
+
28
+ <pre>
29
+ sudo env ARCHFLAGS="-arch i386" gem install bdb --source http://gemcutter.org -- --with-db-dir=/usr/local/BerkeleyDB.4.8
30
+ </pre>
31
+
32
+ For Berkeley DB v4.7 installed from MacPorts do the following:
33
+
34
+ <pre>
35
+ sudo env ARCHFLAGS="-arch i386" gem install bdb --source http://gemcutter.org -- --with-db-include=/opt/local/include/db47 --with-db-lib=/opt/local/lib/db47
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_reference/C/frame_main.html":http://www.oracle.com/technology/documentation/berkeley-db/db/api_reference/C/frame_main.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/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,3025 @@
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
+ }
628
+ data.flags = DB_DBT_MALLOC;
629
+
630
+ rv = dbh->db->get(dbh->db,txn?txn->txn:NULL,&key,&data,flags);
631
+ if ( rv == 0 ) {
632
+ str = rb_str_new(data.data,data.size);
633
+ if (data.data) free(data.data);
634
+ return str;
635
+ } else if (rv == DB_NOTFOUND) {
636
+ return Qnil;
637
+ } else {
638
+ raise_error(rv, "db_get failure: %s",db_strerror(rv));
639
+ }
640
+ return Qnil;
641
+ }
642
+
643
+ /*
644
+ * call-seq:
645
+ * db.pget(txn,key,data,flags) -> [pkey,data]
646
+ *
647
+ * get a key/data pair from database using a secondary index.
648
+ * returns an array with a primary key and the data element.
649
+ *
650
+ */
651
+ VALUE db_pget(VALUE obj, VALUE vtxn, VALUE vkey, VALUE vdata, VALUE vflags)
652
+ {
653
+ t_dbh *dbh;
654
+ int rv;
655
+ u_int32_t flags=0;
656
+ DBT key,data,pkey;
657
+ VALUE str;
658
+ t_txnh *txn=NULL;
659
+
660
+ memset(&key,0,sizeof(DBT));
661
+ memset(&data,0,sizeof(DBT));
662
+ memset(&pkey,0,sizeof(DBT));
663
+
664
+ if ( ! NIL_P(vtxn) ) {
665
+ Data_Get_Struct(vtxn,t_txnh,txn);
666
+ if (!txn->txn)
667
+ raise(0, "txn is closed");
668
+ }
669
+
670
+ if ( ! NIL_P(vflags) ) {
671
+ flags=NUM2UINT(vflags);
672
+ }
673
+
674
+ Data_Get_Struct(obj,t_dbh,dbh);
675
+ if (!dbh->db)
676
+ raise(0, "db is closed");
677
+
678
+ StringValue(vkey);
679
+
680
+ key.data = RSTRING_PTR(vkey);
681
+ key.size = RSTRING_LEN(vkey);
682
+ key.flags = LMEMFLAG;
683
+
684
+ if ( ! NIL_P(vdata) ) {
685
+ StringValue(vdata);
686
+ data.data = RSTRING_PTR(vdata);
687
+ data.size = RSTRING_LEN(vdata);
688
+ data.flags = LMEMFLAG;
689
+ }
690
+
691
+ rv = dbh->db->pget(dbh->db,txn?txn->txn:NULL,&key,&pkey,&data,flags);
692
+ if ( rv == 0 ) {
693
+ return
694
+ rb_ary_new3(2,
695
+ rb_str_new(pkey.data,pkey.size),
696
+ rb_str_new(data.data,data.size));
697
+
698
+ } else if (rv == DB_NOTFOUND) {
699
+ return Qnil;
700
+ } else {
701
+ raise_error(rv, "db_pget failure: %s",db_strerror(rv));
702
+ }
703
+ return Qnil;
704
+ }
705
+
706
+ /*
707
+ * call-seq:
708
+ * db[key] -> data
709
+ *
710
+ * array ref style data retrieval
711
+ *
712
+ */
713
+ VALUE db_aget(VALUE obj, VALUE vkey)
714
+ {
715
+ return db_get(obj,Qnil,vkey,Qnil,Qnil);
716
+ }
717
+
718
+ /*
719
+ * call-seq:
720
+ * db[key]=data
721
+ *
722
+ * array ref style data storage
723
+ */
724
+ VALUE db_aset(VALUE obj, VALUE vkey, VALUE vdata)
725
+ {
726
+ return db_put(obj,Qnil,vkey,vdata,Qnil);
727
+ }
728
+
729
+ /*
730
+ * call-seq:
731
+ * db.join([cursors],flags) -> join_cursor
732
+ *
733
+ * create a join cursor from an array of cursors.
734
+ * The input cursors will usually be set_range and, if duplicate
735
+ * data items are allowed the should be DUP_SORT or the performance
736
+ * will be abysmal.
737
+ */
738
+ VALUE db_join(VALUE obj, VALUE vacurs, VALUE vflags)
739
+ {
740
+ t_dbh *dbh;
741
+ t_dbch *dbch;
742
+ u_int32_t flags;
743
+ DBC **curs;
744
+ int i,rv;
745
+ VALUE jcurs;
746
+
747
+ flags=NUM2UINT(vflags);
748
+ Data_Get_Struct(obj,t_dbh,dbh);
749
+ if (!dbh->db)
750
+ raise(0, "db is closed");
751
+
752
+ curs = ALLOCA_N(DBC *,RARRAY(vacurs)->len);
753
+ for (i=0; i<RARRAY(vacurs)->len; i++) {
754
+ Data_Get_Struct(RARRAY(vacurs)->ptr[i],t_dbch,dbch);
755
+ /* cursor is closed? */
756
+ curs[i]=dbch->dbc;
757
+ }
758
+ curs[i]=NULL;
759
+ jcurs=Data_Make_Struct(cCursor,t_dbch,dbc_mark,dbc_free,dbch);
760
+ rv = dbh->db->join(dbh->db,curs,&(dbch->dbc),flags);
761
+ if (rv) {
762
+ raise_error(rv, "db_join: %s",db_strerror(rv));
763
+ }
764
+ dbch->db=dbh;
765
+ rb_ary_push(dbch->db->adbc,jcurs);
766
+ rb_obj_call_init(jcurs,0,NULL);
767
+ return jcurs;
768
+ }
769
+
770
+ #if DB_VERSION_MINOR > 3
771
+ /*
772
+ * call-seq:
773
+ * db.compact(txn,start_key,stop_key,compact_opts,flags) -> end_key
774
+ *
775
+ * compact the database (4.4 an up). start and stop keys limit the
776
+ * range of compaction in BTREE types. compact_opts is currently
777
+ * ignored. Call returns the last key compacted (could be fed into
778
+ * a subsequent call as the start_key).
779
+ *
780
+ */
781
+ VALUE db_compact(VALUE obj, VALUE vtxn, VALUE vstart_key,
782
+ VALUE vstop_key, VALUE db_compact,
783
+ VALUE vflags)
784
+ {
785
+ t_dbh *dbh;
786
+ u_int32_t flags;
787
+ t_txnh *txn=NULL;
788
+ DBT start_key, stop_key, end_key;
789
+ int rv;
790
+
791
+ flags=NUM2UINT(vflags);
792
+ Data_Get_Struct(obj,t_dbh,dbh);
793
+ if (!dbh->db)
794
+ raise(0, "db is closed");
795
+
796
+ memset(&start_key,0,sizeof(DBT));
797
+ memset(&stop_key,0,sizeof(DBT));
798
+ memset(&end_key,0,sizeof(DBT));
799
+
800
+ if ( ! NIL_P(vstart_key) ) {
801
+ StringValue(vstart_key);
802
+ start_key.data=RSTRING_PTR(vstart_key);
803
+ start_key.size=RSTRING_LEN(vstart_key);
804
+ start_key.flags= LMEMFLAG;
805
+ }
806
+ if ( ! NIL_P(vstop_key) ) {
807
+ StringValue(vstop_key);
808
+ stop_key.data=RSTRING_PTR(vstop_key);
809
+ stop_key.size=RSTRING_LEN(vstop_key);
810
+ stop_key.flags= LMEMFLAG;
811
+ }
812
+ if ( ! NIL_P(vtxn) ) {
813
+ Data_Get_Struct(vtxn,t_txnh,txn);
814
+ if (!txn->txn)
815
+ raise(0, "txn is closed");
816
+ }
817
+
818
+ rv=dbh->db->compact(dbh->db,txn?txn->txn:NULL,
819
+ &start_key,
820
+ &stop_key,
821
+ NULL,
822
+ flags,
823
+ &end_key);
824
+ if (rv)
825
+ raise_error(rv,"db_compact failure: %s",db_strerror(rv));
826
+
827
+ return rb_str_new(end_key.data,end_key.size);
828
+
829
+ }
830
+ #endif
831
+
832
+ /*
833
+ * call-seq:
834
+ * db.get_byteswapped -> true/false
835
+ *
836
+ * true if database is running in swapped mode. This happens when
837
+ * the db is created on a machine with a different endian.
838
+ */
839
+ VALUE db_get_byteswapped(VALUE obj)
840
+ {
841
+ t_dbh *dbh;
842
+ int rv;
843
+ int is_swapped;
844
+
845
+ Data_Get_Struct(obj,t_dbh,dbh);
846
+ if (!dbh->db)
847
+ raise(0, "db is closed");
848
+ rv=dbh->db->get_byteswapped(dbh->db,&is_swapped);
849
+ if (rv)
850
+ raise_error(rv,"db_get_byteswapped failed: %s",db_strerror(rv));
851
+ if (is_swapped)
852
+ return Qtrue;
853
+ else
854
+ return Qfalse;
855
+ }
856
+
857
+ /*
858
+ * call-seq:
859
+ * db.get_type -> Fixnum(type)
860
+ *
861
+ * an integer indicating the type of db (BTREE, HASH, etc).
862
+ */
863
+ VALUE db_get_type(VALUE obj)
864
+ {
865
+ t_dbh *dbh;
866
+ int rv;
867
+ DBTYPE dbtype;
868
+
869
+ Data_Get_Struct(obj,t_dbh,dbh);
870
+ if (!dbh->db)
871
+ raise(0, "db is closed");
872
+ rv=dbh->db->get_type(dbh->db,&dbtype);
873
+ if (rv)
874
+ raise_error(rv,"db_get_type failed: %s",db_strerror(rv));
875
+ return INT2FIX(dbtype);
876
+ }
877
+
878
+ /*
879
+ * call-seq:
880
+ * db.remove(disk_file,logical_db,flags) -> true
881
+ *
882
+ * removes a whole database file, or just a logical_db within
883
+ * that file, i.e. if file and logical are both specified, only
884
+ * the logical will be removed. the Bdb::Db instance cannot have
885
+ * been previously used for anything and cannot be used after.
886
+ */
887
+ VALUE db_remove(VALUE obj, VALUE vdisk_file,
888
+ VALUE vlogical_db, VALUE vflags)
889
+ {
890
+ t_dbh *dbh;
891
+ int rv;
892
+ u_int32_t flags=0;
893
+ char *logical_db=NULL;
894
+
895
+ if ( ! NIL_P(vflags) )
896
+ flags=NUM2UINT(vflags);
897
+
898
+ Data_Get_Struct(obj,t_dbh,dbh);
899
+ if (!dbh->db)
900
+ raise(0, "db is closed");
901
+ rv=dbh->db->remove(dbh->db,
902
+ NIL_P(vdisk_file)?NULL:StringValueCStr(vdisk_file),
903
+ NIL_P(vlogical_db)?NULL:StringValueCStr(vlogical_db),
904
+ flags);
905
+ /* handle cannot be accessed again per docs */
906
+ dbh->db=NULL;
907
+ if (rv)
908
+ raise_error(rv,"db_remove failed: %s",db_strerror(rv));
909
+ return Qtrue;
910
+ }
911
+
912
+ /*
913
+ * call-seq:
914
+ * db.rename(file,logical,newname,flags) -> true
915
+ *
916
+ * rename a file or logical db to newname.
917
+ */
918
+ VALUE db_rename(VALUE obj, VALUE vdisk_file,
919
+ VALUE vlogical_db, VALUE newname, VALUE vflags)
920
+ {
921
+ t_dbh *dbh;
922
+ int rv;
923
+ u_int32_t flags=0;
924
+ char *disk_file=NULL;
925
+ char *logical_db=NULL;
926
+
927
+ if ( ! NIL_P(vflags) )
928
+ flags=NUM2UINT(vflags);
929
+
930
+ if ( NIL_P(newname) )
931
+ raise_error(0,"db_rename newname must be specified");
932
+
933
+ Data_Get_Struct(obj,t_dbh,dbh);
934
+ if (!dbh->db)
935
+ raise(0, "db is closed");
936
+ rv=dbh->db->rename(dbh->db,
937
+ NIL_P(vdisk_file)?NULL:StringValueCStr(vdisk_file),
938
+ NIL_P(vlogical_db)?NULL:StringValueCStr(vlogical_db),
939
+ StringValueCStr(newname),
940
+ flags);
941
+
942
+ if (rv) {
943
+ raise_error(rv,"db_rename failed: %s",db_strerror(rv));
944
+ }
945
+ return Qtrue;
946
+ }
947
+
948
+ /*
949
+ * call-seq:
950
+ * db.sync -> true
951
+ *
952
+ * sync the database out to storage.
953
+ */
954
+ VALUE db_sync(VALUE obj)
955
+ {
956
+ t_dbh *dbh;
957
+ int rv;
958
+
959
+ Data_Get_Struct(obj,t_dbh,dbh);
960
+ if (!dbh->db)
961
+ raise(0, "db is closed");
962
+ rv=dbh->db->sync(dbh->db,NOFLAGS);
963
+
964
+ if (rv)
965
+ raise_error(rv,"db_sync failed: %s",db_strerror(rv));
966
+ return Qtrue;
967
+ }
968
+
969
+ /*
970
+ * call-seq:
971
+ * db.truncate(txn) -> Fixnum(record_count)
972
+ *
973
+ * truncate, i.e. remove all records, purge, trash.
974
+ *
975
+ */
976
+ VALUE db_truncate(VALUE obj, VALUE vtxn)
977
+ {
978
+ t_dbh *dbh;
979
+ t_txnh *txn=NULL;
980
+ int rv;
981
+ VALUE result;
982
+ u_int32_t count;
983
+
984
+ if ( ! NIL_P(vtxn) ) {
985
+ Data_Get_Struct(vtxn,t_txnh,txn);
986
+ if (!txn->txn)
987
+ raise(0, "txn is closed");
988
+ }
989
+
990
+ Data_Get_Struct(obj,t_dbh,dbh);
991
+ if (!dbh->db)
992
+ raise(0, "db is closed");
993
+
994
+ rv=dbh->db->truncate(dbh->db,txn?txn->txn:NULL,&count,NOFLAGS);
995
+ if (rv)
996
+ raise_error(rv,"db_truncate: %s",db_strerror(rv));
997
+
998
+ return INT2FIX(count);
999
+ }
1000
+
1001
+ /*
1002
+ * call-seq:
1003
+ * db.key_range(txn,vkey,flags) -> [#less,#same,#greater]
1004
+ *
1005
+ * calculate position of key within database. returns the counts
1006
+ * of keys less, same and greater than the given key as an
1007
+ * array of Fixnum-s
1008
+ */
1009
+ VALUE db_key_range(VALUE obj, VALUE vtxn, VALUE vkey, VALUE vflags)
1010
+ {
1011
+ t_dbh *dbh;
1012
+ t_txnh *txn=NULL;
1013
+ DBT key;
1014
+ u_int32_t flags;
1015
+ int rv;
1016
+ DB_KEY_RANGE key_range;
1017
+ VALUE result;
1018
+
1019
+ if ( ! NIL_P(vtxn) ) {
1020
+ Data_Get_Struct(vtxn,t_txnh,txn);
1021
+ if (!txn->txn)
1022
+ raise(0, "txn is closed");
1023
+ }
1024
+
1025
+ if ( ! NIL_P(vflags) )
1026
+ flags=NUM2UINT(vflags);
1027
+
1028
+ Data_Get_Struct(obj,t_dbh,dbh);
1029
+ if (!dbh->db)
1030
+ raise(0, "db is closed");
1031
+
1032
+ memset(&key,0,sizeof(DBT));
1033
+ StringValue(vkey);
1034
+ key.data = RSTRING_PTR(vkey);
1035
+ key.size = RSTRING_LEN(vkey);
1036
+ key.flags = LMEMFLAG;
1037
+
1038
+ rv=dbh->db->key_range(dbh->db,txn?txn->txn:NULL,&key,
1039
+ &key_range,flags);
1040
+ if (rv)
1041
+ raise_error(rv,"db_key_range: %s",db_strerror(rv));
1042
+
1043
+ result=rb_ary_new3(3,
1044
+ rb_float_new(key_range.less),
1045
+ rb_float_new(key_range.equal),
1046
+ rb_float_new(key_range.greater));
1047
+ return result;
1048
+ }
1049
+
1050
+ /*
1051
+ * call-seq:
1052
+ * db.del(txn,key,flags) -> true/nil
1053
+ *
1054
+ * delete records with the key given. DUP values will removed
1055
+ * as a group. true if deleted extant records. NIL if the
1056
+ * operation resulted in DB indicating DB_NOTFOUND.
1057
+ *
1058
+ */
1059
+ VALUE db_del(VALUE obj, VALUE vtxn, VALUE vkey, VALUE vflags)
1060
+ {
1061
+ t_dbh *dbh;
1062
+ int rv;
1063
+ u_int32_t flags;
1064
+ DBT key;
1065
+ VALUE str;
1066
+ t_txnh *txn=NULL;
1067
+
1068
+ memset(&key,0,sizeof(DBT));
1069
+
1070
+ if ( ! NIL_P(vtxn) ) {
1071
+ Data_Get_Struct(vtxn,t_txnh,txn);
1072
+ if (!txn->txn)
1073
+ raise(0, "txn is closed");
1074
+ }
1075
+
1076
+ flags=NUM2UINT(vflags);
1077
+ Data_Get_Struct(obj,t_dbh,dbh);
1078
+ if (!dbh->db)
1079
+ raise(0, "db is closed");
1080
+
1081
+ StringValue(vkey);
1082
+ key.data = RSTRING_PTR(vkey);
1083
+ key.size = RSTRING_LEN(vkey);
1084
+ key.flags = LMEMFLAG;
1085
+
1086
+ rv = dbh->db->del(dbh->db,txn?txn->txn:NULL,&key,flags);
1087
+ if ( rv == DB_NOTFOUND ) {
1088
+ return Qnil;
1089
+ } else if (rv != 0) {
1090
+ raise_error(rv, "db_del failure: %s",db_strerror(rv));
1091
+ }
1092
+ return Qtrue;
1093
+ }
1094
+
1095
+ void assoc_key(DBT* result, VALUE obj) {
1096
+ VALUE key = StringValue(obj);
1097
+ int len = RSTRING_LEN(key);
1098
+ char *str = malloc(len);
1099
+ memcpy(str, RSTRING_PTR(key), len);
1100
+
1101
+ #ifdef DEBUG_DB
1102
+ fprintf(stderr,"assoc_key %*s", len, str);
1103
+ #endif
1104
+
1105
+ result->size = len;
1106
+ result->flags = LMEMFLAG | DB_DBT_APPMALLOC;
1107
+ result->data = str;
1108
+ }
1109
+
1110
+ VALUE assoc_call(VALUE *args)
1111
+ {
1112
+ return rb_funcall(args[0],fv_call,3,args[1],args[2],args[3]);
1113
+ }
1114
+
1115
+ VALUE assoc_rescue(VALUE *error, VALUE e)
1116
+ {
1117
+ VALUE message = StringValue(e);
1118
+ rb_warn(RSTRING_PTR(message));
1119
+ *error = e;
1120
+ }
1121
+
1122
+ int assoc_callback(DB *secdb, const DBT* pkey, const DBT* data, DBT* skey)
1123
+ {
1124
+ t_dbh *dbh;
1125
+ VALUE proc;
1126
+ VALUE error = Qnil;
1127
+ VALUE retv;
1128
+ VALUE args[4];
1129
+ VALUE keys;
1130
+ int i;
1131
+
1132
+ memset(skey,0,sizeof(DBT));
1133
+ dbh=secdb->app_private;
1134
+
1135
+ args[0]=dbh->aproc;
1136
+ args[1]=dbh->self;
1137
+ args[2]=rb_str_new(pkey->data,pkey->size);
1138
+ args[3]=rb_str_new(data->data,data->size);
1139
+
1140
+ #ifdef DEBUG_DB
1141
+ fprintf(stderr,"assoc_data %*s", data->size, data->data);
1142
+ #endif
1143
+
1144
+ retv=rb_rescue((VALUE(*)_((VALUE)))assoc_call,(VALUE)args,(VALUE(*)_((VALUE)))assoc_rescue,(VALUE)&error);
1145
+
1146
+ if (!NIL_P(error)) return 99999;
1147
+ if (NIL_P(retv))
1148
+ return DB_DONOTINDEX;
1149
+
1150
+ keys = rb_check_array_type(retv);
1151
+ if (!NIL_P(keys)) {
1152
+ keys = rb_funcall(keys,fv_uniq,0); /* secondary keys must be uniq */
1153
+ switch(RARRAY(keys)->len) {
1154
+ case 0:
1155
+ return DB_DONOTINDEX;
1156
+ case 1:
1157
+ retv=RARRAY(keys)->ptr[0];
1158
+ break;
1159
+ default:
1160
+ skey->size = RARRAY(keys)->len;
1161
+ skey->flags = LMEMFLAG | DB_DBT_MULTIPLE | DB_DBT_APPMALLOC;
1162
+ skey->data = malloc(skey->size * sizeof(DBT));
1163
+ memset(skey->data, 0, skey->size * sizeof(DBT));
1164
+
1165
+ for (i=0; i<skey->size; i++) {
1166
+ assoc_key(skey->data + i * sizeof(DBT), (VALUE)RARRAY(keys)->ptr[i]);
1167
+ }
1168
+ return 0;
1169
+ }
1170
+ }
1171
+
1172
+ assoc_key(skey, retv);
1173
+ return 0;
1174
+ }
1175
+
1176
+ /*
1177
+ * call-seq:
1178
+ * db.associate(txn,sec_db,flags,proc)
1179
+ *
1180
+ * associate a secondary index(database) with this (primary)
1181
+ * database. The proc can be nil if the database is only opened
1182
+ * DB_RDONLY.
1183
+ *
1184
+ * call back proc has signature:
1185
+ * proc(secdb,key,value)
1186
+ */
1187
+ VALUE db_associate(VALUE obj, VALUE vtxn, VALUE osecdb,
1188
+ VALUE vflags, VALUE cb_proc)
1189
+ {
1190
+ t_dbh *sdbh,*pdbh;
1191
+ int rv;
1192
+ u_int32_t flags,flagsp,flagss;
1193
+ int fdp;
1194
+ t_txnh *txn=NOTXN;
1195
+
1196
+ flags=NUM2UINT(vflags);
1197
+ Data_Get_Struct(obj,t_dbh,pdbh);
1198
+ if (!pdbh->db)
1199
+ raise(0, "db is closed");
1200
+ Data_Get_Struct(osecdb,t_dbh,sdbh);
1201
+ if (!sdbh->db)
1202
+ raise(0, "sdb is closed");
1203
+
1204
+ if ( ! NIL_P(vtxn) ) {
1205
+ Data_Get_Struct(vtxn,t_txnh,txn);
1206
+ if (!txn->txn)
1207
+ raise(0, "txn is closed");
1208
+ }
1209
+
1210
+ if ( cb_proc == Qnil ) {
1211
+ rb_warning("db_associate: no association may be applied");
1212
+ pdbh->db->get_open_flags(pdbh->db,&flagsp);
1213
+ sdbh->db->get_open_flags(sdbh->db,&flagss);
1214
+ if ( flagsp & DB_RDONLY & flagss ) {
1215
+ rv=pdbh->db->associate(pdbh->db,txn?txn->txn:NULL,
1216
+ sdbh->db,NULL,flags);
1217
+ if (rv)
1218
+ raise_error(rv,"db_associate: %s",db_strerror(rv));
1219
+ return Qtrue;
1220
+ } else {
1221
+ raise_error(0,"db_associate empty associate only available when both DBs opened with DB_RDONLY");
1222
+ }
1223
+ } else if ( rb_obj_is_instance_of(cb_proc,rb_cProc) != Qtrue ) {
1224
+ raise_error(0, "db_associate proc required");
1225
+ }
1226
+
1227
+ sdbh->aproc=cb_proc;
1228
+
1229
+ rv=pdbh->db->associate(pdbh->db,txn?txn->txn:NULL,sdbh->db,assoc_callback,flags);
1230
+ #ifdef DEBUG_DB
1231
+ fprintf(stderr,"file is %d\n",fdp);
1232
+ fprintf(stderr,"assoc done 0x%x\n",sdbh);
1233
+ #endif
1234
+ if (rv != 0) {
1235
+ raise_error(rv, "db_associate failure: %s",db_strerror(rv));
1236
+ }
1237
+ return Qtrue;
1238
+ }
1239
+
1240
+ VALUE
1241
+ bt_compare_callback2(VALUE *args)
1242
+ {
1243
+ return rb_funcall(args[0],fv_call,3,args[1],args[2],args[3]);
1244
+ }
1245
+
1246
+ int bt_compare_callback(DB *db, const DBT* key1, const DBT* key2)
1247
+ {
1248
+ t_dbh *dbh;
1249
+ VALUE proc;
1250
+ int cmp;
1251
+ VALUE retv;
1252
+
1253
+ dbh=db->app_private;
1254
+
1255
+ /* Shouldn't catch exceptions in the callback, because bad sort data will corrupt the BTree.*/
1256
+ retv=rb_funcall(dbh->sproc,fv_call,3,dbh->self,
1257
+ rb_str_new(key1->data,key1->size),rb_str_new(key2->data,key2->size));
1258
+
1259
+ if (!FIXNUM_P(retv))
1260
+ rb_raise(rb_eTypeError,"btree comparison should return Fixnum");
1261
+
1262
+ cmp=FIX2INT(retv);
1263
+
1264
+ #ifdef DEBUG_DB
1265
+ fprintf(stderr,"bt_compare %*s <=> %*s: %d", key1->size, key1->data, key2->size, key2->data, cmp);
1266
+ #endif
1267
+
1268
+ return cmp;
1269
+ }
1270
+
1271
+ /*
1272
+ * call-seq:
1273
+ * db.btree_compare = proc
1274
+ *
1275
+ * set the btree key comparison function to the callback proc.
1276
+ *
1277
+ * callback proc has signature:
1278
+ * proc(db,key1,key2)
1279
+ */
1280
+ VALUE db_btree_compare_set(VALUE obj, VALUE cb_proc)
1281
+ {
1282
+ t_dbh *dbh;
1283
+ int rv;
1284
+
1285
+ Data_Get_Struct(obj,t_dbh,dbh);
1286
+ if (!dbh->db)
1287
+ raise(0, "db is closed");
1288
+
1289
+ if ( rb_obj_is_instance_of(cb_proc,rb_cProc) != Qtrue ) {
1290
+ raise_error(0, "db_associate proc required");
1291
+ }
1292
+
1293
+ dbh->sproc=cb_proc;
1294
+ rv=dbh->db->set_bt_compare(dbh->db,bt_compare_callback);
1295
+
1296
+ #ifdef DEBUG_DB
1297
+ fprintf(stderr,"btree_compare set 0x%x\n",dbh);
1298
+ #endif
1299
+ if (rv != 0) {
1300
+ raise_error(rv, "db_btree_compare_set failure: %s",db_strerror(rv));
1301
+ }
1302
+ return Qtrue;
1303
+ }
1304
+
1305
+ /*
1306
+ * call-seq:
1307
+ * db.cursor(txn,flags)
1308
+ *
1309
+ * open a cursor
1310
+ */
1311
+ VALUE db_cursor(VALUE obj, VALUE vtxn, VALUE vflags)
1312
+ {
1313
+ t_dbh *dbh;
1314
+ int rv;
1315
+ u_int32_t flags;
1316
+ DBC *dbc;
1317
+ t_txnh *txn=NOTXN;
1318
+ VALUE c_obj;
1319
+ t_dbch *dbch;
1320
+
1321
+ flags=NUM2UINT(vflags);
1322
+ Data_Get_Struct(obj,t_dbh,dbh);
1323
+ if (!dbh->db)
1324
+ raise(0, "db is closed");
1325
+
1326
+ c_obj=Data_Make_Struct(cCursor, t_dbch, dbc_mark, dbc_free, dbch);
1327
+
1328
+ if ( ! NIL_P(vtxn) ) {
1329
+ Data_Get_Struct(vtxn,t_txnh,txn);
1330
+ if (!txn->txn)
1331
+ raise(0, "txn is closed");
1332
+ }
1333
+
1334
+ rv=dbh->db->cursor(dbh->db,txn?txn->txn:NULL,&(dbch->dbc),flags);
1335
+ if (rv)
1336
+ raise_error(rv,"db_cursor: %s",db_strerror(rv));
1337
+
1338
+ filename_dup(dbch->filename,dbh->filename);
1339
+ dbch->db=dbh;
1340
+ rb_ary_push(dbch->db->adbc,c_obj);
1341
+ rb_obj_call_init(c_obj,0,NULL);
1342
+ return c_obj;
1343
+ }
1344
+
1345
+ /*
1346
+ * call-seq:
1347
+ * dbc.close -> nil
1348
+ *
1349
+ * close an open cursor
1350
+ */
1351
+ VALUE dbc_close(VALUE obj)
1352
+ {
1353
+ t_dbch *dbch;
1354
+ int rv;
1355
+ Data_Get_Struct(obj,t_dbch,dbch);
1356
+ if ( dbch->dbc ) {
1357
+ rv=dbch->dbc->c_close(dbch->dbc);
1358
+ rb_ary_delete(dbch->db->adbc,obj);
1359
+ dbch->db=NULL;
1360
+ dbch->dbc=NULL;
1361
+ if (rv)
1362
+ raise_error(rv,"dbc_close: %s",db_strerror(rv));
1363
+ }
1364
+ return Qnil;
1365
+ }
1366
+
1367
+ /*
1368
+ * call-seq:
1369
+ * dbc.get(key,data,flags) -> [key,data]
1370
+ *
1371
+ * get data by key or key and data. returns array of key,data
1372
+ */
1373
+ VALUE dbc_get(VALUE obj, VALUE vkey, VALUE vdata, VALUE vflags)
1374
+ {
1375
+ t_dbch *dbch;
1376
+ u_int32_t flags;
1377
+ DBT key,data;
1378
+ VALUE rar;
1379
+ int rv;
1380
+
1381
+ flags=NUM2UINT(vflags);
1382
+ Data_Get_Struct(obj,t_dbch,dbch);
1383
+ if (!dbch->dbc)
1384
+ raise(0, "dbc is closed");
1385
+
1386
+ memset(&key,0,sizeof(DBT));
1387
+ memset(&data,0,sizeof(DBT));
1388
+
1389
+ if ( ! NIL_P(vkey) ) {
1390
+ StringValue(vkey);
1391
+ key.data = RSTRING_PTR(vkey);
1392
+ key.size = RSTRING_LEN(vkey);
1393
+ key.flags = LMEMFLAG;
1394
+ }
1395
+ if ( ! NIL_P(vdata) ) {
1396
+ StringValue(vdata);
1397
+ data.data = RSTRING_PTR(vdata);
1398
+ data.size = RSTRING_LEN(vdata);
1399
+ data.flags = LMEMFLAG;
1400
+ }
1401
+
1402
+ rv = dbch->dbc->c_get(dbch->dbc,&key,&data,flags);
1403
+ if ( rv == 0 ) {
1404
+ rar = rb_ary_new3(2,rb_str_new(key.data,key.size),
1405
+ rb_str_new(data.data,data.size));
1406
+ return rar;
1407
+ } else if (rv == DB_NOTFOUND) {
1408
+ return Qnil;
1409
+ } else {
1410
+ raise_error(rv, "dbc_get %s",db_strerror(rv));
1411
+ }
1412
+ return Qnil;
1413
+ }
1414
+ /*
1415
+ * call-seq:
1416
+ * dbc.pget(key,data,flags) -> [key,pkey,data]
1417
+ *
1418
+ * cursor pget, returns array(key, primary key, data)
1419
+ */
1420
+ VALUE dbc_pget(VALUE obj, VALUE vkey, VALUE vdata, VALUE vflags)
1421
+ {
1422
+ t_dbch *dbch;
1423
+ u_int32_t flags;
1424
+ DBT key,data,pkey;
1425
+ VALUE rar;
1426
+ int rv;
1427
+
1428
+ flags=NUM2UINT(vflags);
1429
+ Data_Get_Struct(obj,t_dbch,dbch);
1430
+ if (!dbch->dbc)
1431
+ raise(0, "dbc is closed");
1432
+
1433
+ memset(&key,0,sizeof(DBT));
1434
+ memset(&data,0,sizeof(DBT));
1435
+ memset(&pkey,0,sizeof(DBT));
1436
+
1437
+ if ( ! NIL_P(vkey) ) {
1438
+ StringValue(vkey);
1439
+ key.data = RSTRING_PTR(vkey);
1440
+ key.size = RSTRING_LEN(vkey);
1441
+ key.flags = LMEMFLAG;
1442
+ }
1443
+ if ( ! NIL_P(vdata) ) {
1444
+ StringValue(vdata);
1445
+ data.data = RSTRING_PTR(vdata);
1446
+ data.size = RSTRING_LEN(vdata);
1447
+ data.flags = LMEMFLAG;
1448
+ }
1449
+
1450
+ rv = dbch->dbc->c_pget(dbch->dbc,&key,&pkey,&data,flags);
1451
+ if ( rv == 0 ) {
1452
+ rar = rb_ary_new3(3,
1453
+ rb_str_new(key.data,key.size),
1454
+ rb_str_new(pkey.data,pkey.size),
1455
+ rb_str_new(data.data,data.size));
1456
+ return rar;
1457
+ } else if (rv == DB_NOTFOUND) {
1458
+ return Qnil;
1459
+ } else {
1460
+ raise_error(rv, "dbc_pget %s",db_strerror(rv));
1461
+ }
1462
+ return Qnil;
1463
+ }
1464
+
1465
+ /*
1466
+ * call-seq:
1467
+ * dbc.put(key,data,flags) -> data
1468
+ *
1469
+ * cursor put key/data
1470
+ */
1471
+ VALUE dbc_put(VALUE obj, VALUE vkey, VALUE vdata, VALUE vflags)
1472
+ {
1473
+ t_dbch *dbch;
1474
+ u_int32_t flags;
1475
+ DBT key,data;
1476
+ int rv;
1477
+
1478
+ if ( NIL_P(vdata) )
1479
+ raise_error(0,"data element is required for put");
1480
+
1481
+ flags=NUM2UINT(vflags);
1482
+ Data_Get_Struct(obj,t_dbch,dbch);
1483
+ if (!dbch->dbc)
1484
+ raise(0, "dbc is closed");
1485
+
1486
+ memset(&key,0,sizeof(DBT));
1487
+ memset(&data,0,sizeof(DBT));
1488
+
1489
+ if ( ! NIL_P(vkey) ) {
1490
+ StringValue(vkey);
1491
+ key.data = RSTRING_PTR(vkey);
1492
+ key.size = RSTRING_LEN(vkey);
1493
+ key.flags = LMEMFLAG;
1494
+ }
1495
+
1496
+ StringValue(vdata);
1497
+ data.data = RSTRING_PTR(vdata);
1498
+ data.size = RSTRING_LEN(vdata);
1499
+ data.flags = LMEMFLAG;
1500
+
1501
+ rv = dbch->dbc->c_put(dbch->dbc,&key,&data,flags);
1502
+ if (rv != 0)
1503
+ raise_error(rv,"dbc_put failure: %s",db_strerror(rv));
1504
+
1505
+ return vdata;
1506
+ }
1507
+
1508
+ /*
1509
+ * call-seq:
1510
+ * dbc.del -> true|nil
1511
+ *
1512
+ * delete tuple at current cursor position. returns true if
1513
+ * something was deleted, nil otherwise (DB_KEYEMPTY)
1514
+ *
1515
+ */
1516
+ VALUE dbc_del(VALUE obj)
1517
+ {
1518
+ t_dbch *dbch;
1519
+ int rv;
1520
+
1521
+ Data_Get_Struct(obj,t_dbch,dbch);
1522
+ if (!dbch->dbc)
1523
+ raise(0, "dbc is closed");
1524
+ rv = dbch->dbc->c_del(dbch->dbc,NOFLAGS);
1525
+ if (rv == DB_KEYEMPTY)
1526
+ return Qnil;
1527
+ else if (rv != 0) {
1528
+ raise_error(rv, "dbc_del failure: %s",db_strerror(rv));
1529
+ }
1530
+ return Qtrue;
1531
+ }
1532
+
1533
+ /*
1534
+ * call-seq:
1535
+ * dbc.count -> Fixnum(count)
1536
+ *
1537
+ * returns cursor count as per DB.
1538
+ */
1539
+ VALUE dbc_count(VALUE obj)
1540
+ {
1541
+ t_dbch *dbch;
1542
+ int rv;
1543
+ db_recno_t count;
1544
+
1545
+ Data_Get_Struct(obj,t_dbch,dbch);
1546
+ if (!dbch->dbc)
1547
+ raise(0, "dbc is closed");
1548
+ rv = dbch->dbc->c_count(dbch->dbc,&count,NOFLAGS);
1549
+ if (rv != 0)
1550
+ raise_error(rv, "db_count failure: %s",db_strerror(rv));
1551
+
1552
+ return INT2FIX(count);
1553
+ }
1554
+
1555
+ static void env_free(void *p)
1556
+ {
1557
+ t_envh *eh;
1558
+ eh=(t_envh *)p;
1559
+
1560
+ #ifdef DEBUG_DB
1561
+ if ( RTEST(ruby_debug) )
1562
+ fprintf(stderr,"%s/%d %s 0x%x\n",__FILE__,__LINE__,"env_free cleanup!",p);
1563
+ #endif
1564
+
1565
+ if ( eh ) {
1566
+ if ( eh->env ) {
1567
+ eh->env->close(eh->env,NOFLAGS);
1568
+ eh->env=NULL;
1569
+ }
1570
+ free(p);
1571
+ }
1572
+ }
1573
+ static void env_mark(t_envh *eh)
1574
+ {
1575
+ rb_gc_mark(eh->adb);
1576
+ rb_gc_mark(eh->atxn);
1577
+ }
1578
+
1579
+ /*
1580
+ * Document-class: Bdb::Env
1581
+ *
1582
+ * Encapsulated DB environment. Create by simple new (with
1583
+ * flags as neede), then open. Database handles created with
1584
+ * env.db -> Bdb::Db object.
1585
+ */
1586
+
1587
+ /*
1588
+ * call-seq:
1589
+ * new(flags) -> object
1590
+ *
1591
+ *
1592
+ */
1593
+ VALUE env_new(VALUE class, VALUE vflags)
1594
+ {
1595
+ t_envh *eh;
1596
+ int rv;
1597
+ u_int32_t flags=0;
1598
+ VALUE obj;
1599
+
1600
+ if ( ! NIL_P(vflags) )
1601
+ flags=NUM2UINT(vflags);
1602
+
1603
+ obj=Data_Make_Struct(class,t_envh,env_mark,env_free,eh);
1604
+ rv=db_env_create(&(eh->env),flags);
1605
+ if ( rv != 0 ) {
1606
+ raise_error(rv,"env_new: %s",db_strerror(rv));
1607
+ return Qnil;
1608
+ }
1609
+ eh->self=obj;
1610
+ eh->adb = rb_ary_new();
1611
+ eh->atxn = rb_ary_new();
1612
+ rb_obj_call_init(obj,0,NULL);
1613
+ return obj;
1614
+ }
1615
+
1616
+ /*
1617
+ * call-seq:
1618
+ * env.open(homedir,flags,mode) -> self
1619
+ *
1620
+ * open an environment
1621
+ */
1622
+ VALUE env_open(VALUE obj, VALUE vhome, VALUE vflags, VALUE vmode)
1623
+ {
1624
+ t_envh *eh;
1625
+ int rv;
1626
+ u_int32_t flags=0;
1627
+ int mode=0;
1628
+
1629
+ if ( ! NIL_P(vflags) )
1630
+ flags=NUM2UINT(vflags);
1631
+ if ( ! NIL_P(vmode) )
1632
+ mode=NUM2INT(vmode);
1633
+ Data_Get_Struct(obj,t_envh,eh);
1634
+ if (!eh->env)
1635
+ raise(0, "env is closed");
1636
+ if ( NIL_P(eh->adb) )
1637
+ raise_error(0,"env handle already used and closed");
1638
+
1639
+ rv = eh->env->open(eh->env,StringValueCStr(vhome),flags,mode);
1640
+ if (rv != 0) {
1641
+ raise_error(rv, "env_open failure: %s",db_strerror(rv));
1642
+ }
1643
+ return obj;
1644
+ }
1645
+
1646
+ VALUE txn_abort(VALUE);
1647
+
1648
+ /*
1649
+ * call-seq:
1650
+ * env.close -> self
1651
+ *
1652
+ * close an environment. Do not use it after you close it.
1653
+ * The close process will automatically abort any open transactions
1654
+ * and close open databases (which also closes open cursors).
1655
+ * But this is just an effort to keep your dbs and envs from
1656
+ * becoming corrupted due to ruby errors that exit
1657
+ * unintentionally. However, to make this at all worth anything
1658
+ * use ObjectSpace.define_finalizer which calls env.close to
1659
+ * approach some assurance of it happening.
1660
+ *
1661
+ */
1662
+ VALUE env_close(VALUE obj)
1663
+ {
1664
+ t_envh *eh;
1665
+ VALUE db;
1666
+ int rv;
1667
+
1668
+ Data_Get_Struct(obj,t_envh,eh);
1669
+ if ( eh->env==NULL )
1670
+ return Qnil;
1671
+
1672
+ if (RARRAY(eh->adb)->len > 0) {
1673
+ rb_warning("%s/%d %s %d",__FILE__,__LINE__,
1674
+ "database handles still open",RARRAY(eh->adb)->len);
1675
+ while (RARRAY(eh->adb)->len > 0)
1676
+ if ((db=rb_ary_pop(eh->adb)) != Qnil ) {
1677
+ rb_warning("%s/%d %s 0x%x",__FILE__,__LINE__,
1678
+ "closing",db);
1679
+ /* this could raise! needs rb_protect */
1680
+ db_close(db,INT2FIX(0));
1681
+ }
1682
+ }
1683
+ if (RARRAY(eh->atxn)->len > 0) {
1684
+ rb_warning("%s/%d %s",__FILE__,__LINE__,
1685
+ "database transactions still open");
1686
+ while ( (db=rb_ary_pop(eh->atxn)) != Qnil ) {
1687
+ /* this could raise! needs rb_protect */
1688
+ txn_abort(db);
1689
+ }
1690
+ }
1691
+
1692
+ if ( RTEST(ruby_debug) )
1693
+ rb_warning("%s/%d %s 0x%x",__FILE__,__LINE__,"env_close!",eh);
1694
+
1695
+ rv = eh->env->close(eh->env,NOFLAGS);
1696
+ eh->env=NULL;
1697
+ eh->adb=Qnil;
1698
+ eh->atxn=Qnil;
1699
+ if ( rv != 0 ) {
1700
+ raise_error(rv, "env_close failure: %s",db_strerror(rv));
1701
+ return Qnil;
1702
+ }
1703
+ return obj;
1704
+ }
1705
+
1706
+ /*
1707
+ * call-seq:
1708
+ * env.db -> Bdb::Db instance
1709
+ *
1710
+ * create a db associated with an environment
1711
+ */
1712
+ VALUE env_db(VALUE obj)
1713
+ {
1714
+ t_envh *eh;
1715
+ VALUE dbo;
1716
+
1717
+ Data_Get_Struct(obj,t_envh,eh);
1718
+ if (!eh->env)
1719
+ raise(0, "env is closed");
1720
+ dbo = Data_Wrap_Struct(cDb,db_mark,db_free,0);
1721
+
1722
+ return db_init_aux(dbo,eh);
1723
+ }
1724
+
1725
+ /*
1726
+ * call-seq:
1727
+ * env.cachesize=Fixnum|Bignum
1728
+ *
1729
+ * set the environment cache size. If it is a Bignum then it
1730
+ * will populate the bytes and gbytes part of the DB struct.
1731
+ * Fixnums will only populate bytes (which is still pretty big).
1732
+ */
1733
+ VALUE env_set_cachesize(VALUE obj, VALUE size)
1734
+ {
1735
+ t_envh *eh;
1736
+ unsigned long long ln;
1737
+ u_int32_t bytes=0,gbytes=0;
1738
+ int rv;
1739
+ Data_Get_Struct(obj,t_envh,eh);
1740
+ if (!eh->env)
1741
+ raise(0, "env is closed");
1742
+
1743
+ if ( TYPE(size) == T_BIGNUM ) {
1744
+ ln = rb_big2ull(size);
1745
+ gbytes = ln / (1024*1024*1024);
1746
+ bytes = ln - (gbytes*1024*1024*1024);
1747
+ } else if (FIXNUM_P(size) ) {
1748
+ bytes=NUM2UINT(size);
1749
+ } else {
1750
+ raise_error(0,"set_cachesize requires number");
1751
+ return Qnil;
1752
+ }
1753
+
1754
+ rv=eh->env->set_cachesize(eh->env,gbytes,bytes,1);
1755
+ if ( rv != 0 ) {
1756
+ raise_error(rv, "set_cachesize failure: %s",db_strerror(rv));
1757
+ return Qnil;
1758
+ }
1759
+
1760
+ return Qtrue;
1761
+ }
1762
+
1763
+ /*
1764
+ * call-seq:
1765
+ * env.cachesize -> Fixnum|Bignum
1766
+ *
1767
+ * return the environment cache size. If it is a Bignum then it
1768
+ * will populate the bytes and gbytes part of the DB struct.
1769
+ * Fixnums will only populate bytes (which is still pretty big).
1770
+ */
1771
+ VALUE env_get_cachesize(VALUE obj)
1772
+ {
1773
+ t_envh *eh;
1774
+ unsigned long long ln;
1775
+ u_int32_t bytes=0,gbytes=0;
1776
+ int ncache;
1777
+ int rv;
1778
+ Data_Get_Struct(obj,t_envh,eh);
1779
+ if (!eh->env)
1780
+ raise(0, "env is closed");
1781
+
1782
+ rv=eh->env->get_cachesize(eh->env,&gbytes,&bytes,&ncache);
1783
+ if ( rv != 0 ) {
1784
+ raise_error(rv, "get_cachesize failure: %s",db_strerror(rv));
1785
+ return Qnil;
1786
+ }
1787
+
1788
+ if (gbytes != 0)
1789
+ return ULL2NUM(gbytes*1024*1024*1024+bytes);
1790
+ else
1791
+ return UINT2NUM(bytes);
1792
+
1793
+ return Qtrue;
1794
+ }
1795
+
1796
+ VALUE env_set_flags(VALUE obj, VALUE vflags, int onoff)
1797
+ {
1798
+ t_envh *eh;
1799
+ int rv;
1800
+ u_int32_t flags;
1801
+
1802
+ Data_Get_Struct(obj,t_envh,eh);
1803
+ if (!eh->env)
1804
+ raise(0, "env is closed");
1805
+ if ( ! NIL_P(vflags) ) {
1806
+ flags=NUM2UINT(vflags);
1807
+
1808
+ rv=eh->env->set_flags(eh->env,flags,onoff);
1809
+
1810
+ if ( rv != 0 ) {
1811
+ raise_error(rv, "set_flags failure: %s",db_strerror(rv));
1812
+ return Qnil;
1813
+ }
1814
+ }
1815
+ return Qtrue;
1816
+ }
1817
+
1818
+ /*
1819
+ * call-seq:
1820
+ * env.flags -> flags
1821
+ *
1822
+ * get what flags are on.
1823
+ */
1824
+ VALUE env_get_flags(VALUE obj)
1825
+ {
1826
+ t_envh *eh;
1827
+ int rv;
1828
+ u_int32_t flags;
1829
+
1830
+ Data_Get_Struct(obj,t_envh,eh);
1831
+ if (!eh->env)
1832
+ raise(0, "env is closed");
1833
+
1834
+ rv=eh->env->get_flags(eh->env,&flags);
1835
+
1836
+ if ( rv != 0 ) {
1837
+ raise_error(rv, "set_flags failure: %s",db_strerror(rv));
1838
+ return Qnil;
1839
+ }
1840
+
1841
+ return UINT2NUM(flags);
1842
+ }
1843
+
1844
+ /*
1845
+ * call-seq:
1846
+ * env.flags_on=flags
1847
+ *
1848
+ * set the 'flags' on. An or'ed set of flags will be set on.
1849
+ * Only included flags will be affected. Serialized calls
1850
+ * will only affect flags indicated (leaving others, default or
1851
+ * set as they were).
1852
+ */
1853
+ VALUE env_set_flags_on(VALUE obj, VALUE vflags)
1854
+ {
1855
+ return env_set_flags(obj,vflags,1);
1856
+ }
1857
+
1858
+ /*
1859
+ * call-seq:
1860
+ * env.flags_off=flags
1861
+ *
1862
+ * set the 'flags' off. An or'ed set of flags will be set off.
1863
+ * Only included flags will be affected. Serialized calls
1864
+ * will only affect flags indicated (leaving others, default or
1865
+ * set as they were).
1866
+ */
1867
+ VALUE env_set_flags_off(VALUE obj, VALUE vflags)
1868
+ {
1869
+ return env_set_flags(obj,vflags,0);
1870
+ }
1871
+
1872
+ /*
1873
+ * call-seq:
1874
+ * env.list_dbs -> [Bdb::Db array]
1875
+ *
1876
+ * return 0 or more open databases within the receiver environment.
1877
+ * If 0, will return [], not nil.
1878
+ */
1879
+ VALUE env_list_dbs(VALUE obj)
1880
+ {
1881
+ t_envh *eh;
1882
+ Data_Get_Struct(obj,t_envh,eh);
1883
+ if (!eh->env)
1884
+ raise(0, "env is closed");
1885
+ return eh->adb;
1886
+ }
1887
+ static void txn_mark(t_txnh *txn)
1888
+ {
1889
+ if (txn->env)
1890
+ rb_gc_mark(txn->env->self);
1891
+ }
1892
+ static void txn_free(t_txnh *txn)
1893
+ {
1894
+ #ifdef DEBUG_DB
1895
+ if ( RTEST(ruby_debug) )
1896
+ fprintf(stderr,"%s/%d %s %p\n",__FILE__,__LINE__,"txn_free",txn);
1897
+ #endif
1898
+
1899
+ if (txn) {
1900
+ if (txn->txn)
1901
+ txn->txn->abort(txn->txn);
1902
+ txn->txn=NULL;
1903
+ if (txn->env) {
1904
+ rb_ary_delete(txn->env->atxn,txn->self);
1905
+ }
1906
+ txn->env=NULL;
1907
+
1908
+ free(txn);
1909
+ }
1910
+ }
1911
+
1912
+ /*
1913
+ * call-seq:
1914
+ * env.txn_begin(txn_parent,flags) -> Bdb::Txn
1915
+ *
1916
+ * start a root transaction or embedded (via txn_parent).
1917
+ */
1918
+ VALUE env_txn_begin(VALUE obj, VALUE vtxn_parent, VALUE vflags)
1919
+ {
1920
+ t_txnh *parent=NULL, *txn=NULL;
1921
+ u_int32_t flags=0;
1922
+ int rv;
1923
+ t_envh *eh;
1924
+ VALUE t_obj;
1925
+
1926
+ if ( ! NIL_P(vflags))
1927
+ flags=NUM2UINT(vflags);
1928
+ if ( ! NIL_P(vtxn_parent) ) {
1929
+ Data_Get_Struct(vtxn_parent,t_txnh,parent);
1930
+ if (!parent->txn)
1931
+ raise(0, "parent txn is closed");
1932
+ }
1933
+
1934
+ Data_Get_Struct(obj,t_envh,eh);
1935
+ if (!eh->env)
1936
+ raise(0, "env is closed");
1937
+ t_obj=Data_Make_Struct(cTxn,t_txnh,txn_mark,txn_free,txn);
1938
+
1939
+ rv=eh->env->txn_begin(eh->env,parent?parent->txn:NULL,
1940
+ &(txn->txn),flags);
1941
+
1942
+ if ( rv != 0 ) {
1943
+ raise_error(rv, "env_txn_begin: %s",db_strerror(rv));
1944
+ return Qnil;
1945
+ }
1946
+ txn->env=eh;
1947
+ txn->self=t_obj;
1948
+ rb_ary_push(eh->atxn,t_obj);
1949
+
1950
+ /* Once we get this working, we'll have to track transactions */
1951
+ rb_obj_call_init(t_obj,0,NULL);
1952
+ return t_obj;
1953
+ }
1954
+
1955
+ /*
1956
+ * call-seq:
1957
+ * env.txn_checkpoint -> true
1958
+ *
1959
+ * Cause env transaction state to be checkpointed.
1960
+ */
1961
+ VALUE env_txn_checkpoint(VALUE obj, VALUE vkbyte, VALUE vmin,
1962
+ VALUE vflags)
1963
+ {
1964
+ u_int32_t flags=0;
1965
+ int rv;
1966
+ t_envh *eh;
1967
+ u_int32_t kbyte=0, min=0;
1968
+
1969
+ if ( ! NIL_P(vflags))
1970
+ flags=NUM2UINT(vflags);
1971
+
1972
+ if ( FIXNUM_P(vkbyte) )
1973
+ kbyte=FIX2UINT(vkbyte);
1974
+
1975
+ if ( FIXNUM_P(vmin) )
1976
+ min=FIX2UINT(vmin);
1977
+
1978
+ Data_Get_Struct(obj,t_envh,eh);
1979
+ if (!eh->env)
1980
+ raise(0, "env is closed");
1981
+ rv=eh->env->txn_checkpoint(eh->env,kbyte,min,flags);
1982
+ if ( rv != 0 ) {
1983
+ raise_error(rv, "env_txn_checkpoint: %s",db_strerror(rv));
1984
+ return Qnil;
1985
+ }
1986
+ return Qtrue;
1987
+ }
1988
+
1989
+ VALUE env_txn_stat_active(DB_TXN_ACTIVE *t)
1990
+ {
1991
+ VALUE ao;
1992
+
1993
+ ao=rb_class_new_instance(0,NULL,cTxnStatActive);
1994
+
1995
+ rb_iv_set(ao,"@txnid",INT2FIX(t->txnid));
1996
+ rb_iv_set(ao,"@parentid",INT2FIX(t->parentid));
1997
+ /* rb_iv_set(ao,"@thread_id",INT2FIX(t->thread_id)); */
1998
+ rb_iv_set(ao,"@lsn",rb_ary_new3(2,
1999
+ INT2FIX(t->lsn.file),
2000
+ INT2FIX(t->lsn.offset)));
2001
+ /* XA status is currently excluded */
2002
+ return ao;
2003
+ }
2004
+
2005
+ /*
2006
+ * call-seq:
2007
+ * db.stat(txn,flags) -> Bdb::Db::Stat
2008
+ *
2009
+ * get database status. Returns a Bdb::Db::Stat object that
2010
+ * is specialized to the db_type and only responds to [] to
2011
+ * retrieve status values. All values are stored in instance
2012
+ * variables, so singleton classes can be created and instance_eval
2013
+ * will work.
2014
+ */
2015
+ VALUE db_stat(VALUE obj, VALUE vtxn, VALUE vflags)
2016
+ {
2017
+ u_int32_t flags=0;
2018
+ int rv;
2019
+ t_dbh *dbh;
2020
+ t_txnh *txn=NULL;
2021
+ DBTYPE dbtype;
2022
+ union {
2023
+ void *stat;
2024
+ DB_HASH_STAT *hstat;
2025
+ DB_BTREE_STAT *bstat;
2026
+ DB_QUEUE_STAT *qstat;
2027
+ } su;
2028
+ VALUE s_obj;
2029
+
2030
+ if ( ! NIL_P(vflags) )
2031
+ flags=NUM2UINT(vflags);
2032
+ if ( ! NIL_P(vtxn) ) {
2033
+ Data_Get_Struct(vtxn,t_txnh,txn);
2034
+ if (!txn->txn)
2035
+ raise(0, "txn is closed");
2036
+ }
2037
+
2038
+ Data_Get_Struct(obj,t_dbh,dbh);
2039
+ if (!dbh->db)
2040
+ raise(0, "db is closed");
2041
+
2042
+ rv=dbh->db->get_type(dbh->db,&dbtype);
2043
+ if (rv)
2044
+ raise_error(rv,"db_stat %s",db_strerror(rv));
2045
+ #if DB_VERSION_MINOR > 2
2046
+ rv=dbh->db->stat(dbh->db,txn?txn->txn:NULL,&(su.stat),flags);
2047
+ #else
2048
+ rv=dbh->db->stat(dbh->db,&(su.stat),flags);
2049
+ #endif
2050
+ if (rv)
2051
+ raise_error(rv,"db_stat %s",db_strerror(rv));
2052
+
2053
+ s_obj=rb_class_new_instance(0,NULL,cDbStat);
2054
+ rb_iv_set(s_obj,"@dbtype",INT2FIX(dbtype));
2055
+
2056
+ switch(dbtype) {
2057
+
2058
+ #define hs_int(field) \
2059
+ rb_iv_set(s_obj,"@" #field,INT2FIX(su.hstat->field))
2060
+
2061
+ case DB_HASH:
2062
+ hs_int(hash_magic);
2063
+ hs_int(hash_version); /* Version number. */
2064
+ hs_int(hash_metaflags); /* Metadata flags. */
2065
+ hs_int(hash_nkeys); /* Number of unique keys. */
2066
+ hs_int(hash_ndata); /* Number of data items. */
2067
+ hs_int(hash_pagesize); /* Page size. */
2068
+ hs_int(hash_ffactor); /* Fill factor specified at create. */
2069
+ hs_int(hash_buckets); /* Number of hash buckets. */
2070
+ hs_int(hash_free); /* Pages on the free list. */
2071
+ hs_int(hash_bfree); /* Bytes free on bucket pages. */
2072
+ hs_int(hash_bigpages); /* Number of big key/data pages. */
2073
+ hs_int(hash_big_bfree); /* Bytes free on big item pages. */
2074
+ hs_int(hash_overflows); /* Number of overflow pages. */
2075
+ hs_int(hash_ovfl_free); /* Bytes free on ovfl pages. */
2076
+ hs_int(hash_dup); /* Number of dup pages. */
2077
+ hs_int(hash_dup_free); /* Bytes free on duplicate pages. */
2078
+ break;
2079
+
2080
+ #define bs_int(field) \
2081
+ rb_iv_set(s_obj,"@" #field,INT2FIX(su.bstat->field))
2082
+
2083
+ case DB_BTREE:
2084
+ case DB_RECNO:
2085
+ bs_int(bt_magic); /* Magic number. */
2086
+ bs_int(bt_version); /* Version number. */
2087
+ bs_int(bt_metaflags); /* Metadata flags. */
2088
+ bs_int(bt_nkeys); /* Number of unique keys. */
2089
+ bs_int(bt_ndata); /* Number of data items. */
2090
+ bs_int(bt_pagesize); /* Page size. */
2091
+ #if DB_VERSION_MINOR < 4
2092
+ bs_int(bt_maxkey); /* Maxkey value. */
2093
+ #endif
2094
+ bs_int(bt_minkey); /* Minkey value. */
2095
+ bs_int(bt_re_len); /* Fixed-length record length. */
2096
+ bs_int(bt_re_pad); /* Fixed-length record pad. */
2097
+ bs_int(bt_levels); /* Tree levels. */
2098
+ bs_int(bt_int_pg); /* Internal pages. */
2099
+ bs_int(bt_leaf_pg); /* Leaf pages. */
2100
+ bs_int(bt_dup_pg); /* Duplicate pages. */
2101
+ bs_int(bt_over_pg); /* Overflow pages. */
2102
+ #if DB_VERSION_MINOR > 2
2103
+ bs_int(bt_empty_pg); /* Empty pages. */
2104
+ #endif
2105
+ bs_int(bt_free); /* Pages on the free list. */
2106
+ bs_int(bt_int_pgfree); /* Bytes free in internal pages. */
2107
+ bs_int(bt_leaf_pgfree); /* Bytes free in leaf pages. */
2108
+ bs_int(bt_dup_pgfree); /* Bytes free in duplicate pages. */
2109
+ bs_int(bt_over_pgfree); /* Bytes free in overflow pages. */
2110
+
2111
+ break;
2112
+
2113
+ #define qs_int(field) \
2114
+ rb_iv_set(s_obj,"@" #field,INT2FIX(su.qstat->field))
2115
+
2116
+ case DB_QUEUE:
2117
+ qs_int(qs_magic); /* Magic number. */
2118
+ qs_int(qs_version); /* Version number. */
2119
+ qs_int(qs_metaflags); /* Metadata flags. */
2120
+ qs_int(qs_nkeys); /* Number of unique keys. */
2121
+ qs_int(qs_ndata); /* Number of data items. */
2122
+ qs_int(qs_pagesize); /* Page size. */
2123
+ qs_int(qs_extentsize); /* Pages per extent. */
2124
+ qs_int(qs_pages); /* Data pages. */
2125
+ qs_int(qs_re_len); /* Fixed-length record length. */
2126
+ qs_int(qs_re_pad); /* Fixed-length record pad. */
2127
+ qs_int(qs_pgfree); /* Bytes free in data pages. */
2128
+ qs_int(qs_first_recno); /* First not deleted record. */
2129
+ qs_int(qs_cur_recno); /* Next available record number. */
2130
+
2131
+ break;
2132
+ }
2133
+
2134
+ free(su.stat);
2135
+ return s_obj;
2136
+ }
2137
+
2138
+ /*
2139
+ * call-seq:
2140
+ * stat[name] -> value
2141
+ *
2142
+ * return status value
2143
+ */
2144
+ VALUE stat_aref(VALUE obj, VALUE vname)
2145
+ {
2146
+ rb_iv_get(obj,RSTRING_PTR(rb_str_concat(rb_str_new2("@"),vname)));
2147
+ }
2148
+
2149
+ /*
2150
+ * call-seq:
2151
+ * env.txn_stat -> Bdb::TxnStat
2152
+ *
2153
+ * get the environment transaction status. Each active
2154
+ * transaction will be contained within a Bdb::TxnStat::Active
2155
+ * class.
2156
+ */
2157
+ VALUE env_txn_stat(VALUE obj, VALUE vflags)
2158
+ {
2159
+ u_int32_t flags=0;
2160
+ int rv;
2161
+ t_envh *eh;
2162
+ DB_TXN_STAT *statp;
2163
+ VALUE s_obj;
2164
+ VALUE active;
2165
+ int i;
2166
+
2167
+ if ( ! NIL_P(vflags))
2168
+ flags=NUM2UINT(vflags);
2169
+
2170
+ Data_Get_Struct(obj,t_envh,eh);
2171
+ if (!eh->env)
2172
+ raise(0, "env is closed");
2173
+
2174
+ /* statp will need free() */
2175
+ rv=eh->env->txn_stat(eh->env,&statp,flags);
2176
+ if ( rv != 0 ) {
2177
+ raise_error(rv, "txn_stat: %s",db_strerror(rv));
2178
+ }
2179
+
2180
+ s_obj=rb_class_new_instance(0,NULL,cTxnStat);
2181
+ rb_iv_set(s_obj,"@st_last_ckp",
2182
+ rb_ary_new3(2,
2183
+ INT2FIX(statp->st_last_ckp.file),
2184
+ INT2FIX(statp->st_last_ckp.offset)) );
2185
+ rb_iv_set(s_obj,"@st_time_ckp",
2186
+ rb_time_new(statp->st_time_ckp,0));
2187
+ rb_iv_set(s_obj,"@st_last_txnid",
2188
+ INT2FIX(statp->st_last_txnid));
2189
+ rb_iv_set(s_obj,"@st_maxtxns",
2190
+ INT2FIX(statp->st_maxtxns));
2191
+ rb_iv_set(s_obj,"@st_nactive",
2192
+ INT2FIX(statp->st_nactive));
2193
+ rb_iv_set(s_obj,"@st_maxnactive",
2194
+ INT2FIX(statp->st_maxnactive));
2195
+ rb_iv_set(s_obj,"@st_nbegins",
2196
+ INT2FIX(statp->st_nbegins));
2197
+ rb_iv_set(s_obj,"@st_naborts",
2198
+ INT2FIX(statp->st_naborts));
2199
+ rb_iv_set(s_obj,"@st_ncommits",
2200
+ INT2FIX(statp->st_ncommits));
2201
+ rb_iv_set(s_obj,"@st_nrestores",
2202
+ INT2FIX(statp->st_nrestores));
2203
+ rb_iv_set(s_obj,"@st_regsize",
2204
+ INT2FIX(statp->st_regsize));
2205
+ rb_iv_set(s_obj,"@st_region_wait",
2206
+ INT2FIX(statp->st_region_wait));
2207
+ rb_iv_set(s_obj,"@st_region_nowait",
2208
+ INT2FIX(statp->st_region_nowait));
2209
+ rb_iv_set(s_obj,"@st_txnarray",
2210
+ active=rb_ary_new2(statp->st_nactive));
2211
+
2212
+ for (i=0; i<statp->st_nactive; i++) {
2213
+ rb_ary_push(active,env_txn_stat_active(&(statp->st_txnarray[i])));
2214
+ }
2215
+
2216
+ free(statp);
2217
+ return s_obj;
2218
+ }
2219
+
2220
+ /*
2221
+ * call-seq:
2222
+ * env.set_timeout(timeout,flags) -> timeout
2223
+ *
2224
+ * set lock and transaction timeout
2225
+ */
2226
+ VALUE env_set_timeout(VALUE obj, VALUE vtimeout, VALUE vflags)
2227
+ {
2228
+ t_envh *eh;
2229
+ u_int32_t flags=0;
2230
+ db_timeout_t timeout;
2231
+ int rv;
2232
+
2233
+ if ( ! NIL_P(vflags))
2234
+ flags=NUM2UINT(vflags);
2235
+ timeout=FIX2UINT(vtimeout);
2236
+
2237
+ Data_Get_Struct(obj,t_envh,eh);
2238
+ if (!eh->env)
2239
+ raise(0, "env is closed");
2240
+ rv=eh->env->set_timeout(eh->env,timeout,flags);
2241
+ if ( rv != 0 ) {
2242
+ raise_error(rv, "env_set_timeout: %s",db_strerror(rv));
2243
+ }
2244
+
2245
+ return vtimeout;
2246
+ }
2247
+
2248
+ /*
2249
+ * call-seq:
2250
+ * env.get_timeout(flags) -> Fixnum
2251
+ *
2252
+ * Get current transaction and lock timeout value
2253
+ */
2254
+ VALUE env_get_timeout(VALUE obj, VALUE vflags)
2255
+ {
2256
+ t_envh *eh;
2257
+ u_int32_t flags=0;
2258
+ db_timeout_t timeout;
2259
+ int rv;
2260
+
2261
+ if ( ! NIL_P(vflags))
2262
+ flags=NUM2UINT(vflags);
2263
+
2264
+ Data_Get_Struct(obj,t_envh,eh);
2265
+ if (!eh->env)
2266
+ raise(0, "env is closed");
2267
+ rv=eh->env->get_timeout(eh->env,&timeout,flags);
2268
+ if ( rv != 0 ) {
2269
+ raise_error(rv, "env_get_timeout: %s",db_strerror(rv));
2270
+ }
2271
+
2272
+ return INT2FIX(timeout);
2273
+ }
2274
+
2275
+ /*
2276
+ * call-seq:
2277
+ * env.set_tx_max(max) -> max
2278
+ *
2279
+ * Set the maximum number of transactions with the environment
2280
+ */
2281
+ VALUE env_set_tx_max(VALUE obj, VALUE vmax)
2282
+ {
2283
+ t_envh *eh;
2284
+ u_int32_t max;
2285
+ int rv;
2286
+
2287
+ max=FIX2UINT(vmax);
2288
+
2289
+ Data_Get_Struct(obj,t_envh,eh);
2290
+ if (!eh->env)
2291
+ raise(0, "env is closed");
2292
+ rv=eh->env->set_tx_max(eh->env,max);
2293
+ if ( rv != 0 ) {
2294
+ raise_error(rv, "env_set_tx_max: %s",db_strerror(rv));
2295
+ }
2296
+
2297
+ return vmax;
2298
+ }
2299
+
2300
+ /*
2301
+ * call-seq
2302
+ * env.get_tx_max -> Fixnum
2303
+ *
2304
+ * Get current maximum number of transactions
2305
+ */
2306
+ VALUE env_get_tx_max(VALUE obj)
2307
+ {
2308
+ t_envh *eh;
2309
+ u_int32_t max;
2310
+ int rv;
2311
+
2312
+ Data_Get_Struct(obj,t_envh,eh);
2313
+ if (!eh->env)
2314
+ raise(0, "env is closed");
2315
+ rv=eh->env->get_tx_max(eh->env,&max);
2316
+ if ( rv != 0 ) {
2317
+ raise_error(rv, "env_get_tx_max: %s",db_strerror(rv));
2318
+ }
2319
+
2320
+ return INT2FIX(max);
2321
+ }
2322
+
2323
+ /*
2324
+ * call-seq:
2325
+ * env.mutex_set_max(max) -> max
2326
+ *
2327
+ * Set the maximum number of mutexes with the environment
2328
+ */
2329
+ VALUE env_mutex_set_max(VALUE obj, VALUE vmax)
2330
+ {
2331
+ t_envh *eh;
2332
+ u_int32_t max;
2333
+ int rv;
2334
+
2335
+ max=FIX2UINT(vmax);
2336
+
2337
+ Data_Get_Struct(obj,t_envh,eh);
2338
+ if (!eh->env)
2339
+ raise(0, "env is closed");
2340
+ rv=eh->env->mutex_set_max(eh->env,max);
2341
+ if ( rv != 0 ) {
2342
+ raise_error(rv, "env_mutex_set_max: %s",db_strerror(rv));
2343
+ }
2344
+
2345
+ return vmax;
2346
+ }
2347
+
2348
+ /*
2349
+ * call-seq
2350
+ * env.mutex_get_max -> Fixnum
2351
+ *
2352
+ * Get current maximum number of mutexes.
2353
+ */
2354
+ VALUE env_mutex_get_max(VALUE obj)
2355
+ {
2356
+ t_envh *eh;
2357
+ u_int32_t max;
2358
+ int rv;
2359
+
2360
+ Data_Get_Struct(obj,t_envh,eh);
2361
+ if (!eh->env)
2362
+ raise(0, "env is closed");
2363
+ rv=eh->env->mutex_get_max(eh->env,&max);
2364
+ if ( rv != 0 ) {
2365
+ raise_error(rv, "env_mutex_get_max: %s",db_strerror(rv));
2366
+ }
2367
+
2368
+ return INT2FIX(max);
2369
+ }
2370
+
2371
+ /*
2372
+ * call-seq:
2373
+ * env.set_shm_key(key) -> max
2374
+ *
2375
+ * Set the shared memory key base
2376
+ */
2377
+ VALUE env_set_shm_key(VALUE obj, VALUE vkey)
2378
+ {
2379
+ t_envh *eh;
2380
+ long key;
2381
+ int rv;
2382
+
2383
+ key=FIX2UINT(vkey);
2384
+
2385
+ Data_Get_Struct(obj,t_envh,eh);
2386
+ if (!eh->env)
2387
+ raise(0, "env is closed");
2388
+ rv=eh->env->set_shm_key(eh->env,key);
2389
+ if ( rv != 0 ) {
2390
+ raise_error(rv, "env_set_shm_key: %s",db_strerror(rv));
2391
+ }
2392
+
2393
+ return vkey;
2394
+ }
2395
+
2396
+ /*
2397
+ * call-seq
2398
+ * env.get_shm_key -> Fixnum
2399
+ *
2400
+ * Get the current shm key base
2401
+ */
2402
+ VALUE env_get_shm_key(VALUE obj)
2403
+ {
2404
+ t_envh *eh;
2405
+ long key;
2406
+ int rv;
2407
+
2408
+ Data_Get_Struct(obj,t_envh,eh);
2409
+ if (!eh->env)
2410
+ raise(0, "env is closed");
2411
+ rv=eh->env->get_shm_key(eh->env,&key);
2412
+ if ( rv != 0 ) {
2413
+ raise_error(rv, "env_get_shm_key: %s",db_strerror(rv));
2414
+ }
2415
+
2416
+ return INT2FIX(key);
2417
+ }
2418
+
2419
+ /*
2420
+ * call-seq:
2421
+ * env.set_lk_detect(detect) -> detect
2422
+ *
2423
+ * Set when lock detector should be run
2424
+ */
2425
+ VALUE env_set_lk_detect(VALUE obj, VALUE vdetect)
2426
+ {
2427
+ t_envh *eh;
2428
+ u_int32_t detect;
2429
+ int rv;
2430
+
2431
+ detect=NUM2UINT(vdetect);
2432
+
2433
+ Data_Get_Struct(obj,t_envh,eh);
2434
+ if (!eh->env)
2435
+ raise(0, "env is closed");
2436
+ rv=eh->env->set_lk_detect(eh->env,detect);
2437
+ if ( rv != 0 ) {
2438
+ raise_error(rv, "env_set_lk_detect: %s",db_strerror(rv));
2439
+ }
2440
+
2441
+ return vdetect;
2442
+ }
2443
+
2444
+ /*
2445
+ * call-seq:
2446
+ * env.get_lk_detect() -> detect
2447
+ *
2448
+ * Get when lock detector should be run
2449
+ */
2450
+ VALUE env_get_lk_detect(VALUE obj)
2451
+ {
2452
+ t_envh *eh;
2453
+ u_int32_t detect;
2454
+ int rv;
2455
+
2456
+ Data_Get_Struct(obj,t_envh,eh);
2457
+ if (!eh->env)
2458
+ raise(0, "env is closed");
2459
+ rv=eh->env->get_lk_detect(eh->env,&detect);
2460
+ if ( rv != 0 ) {
2461
+ raise_error(rv, "env_set_lk_detect: %s",db_strerror(rv));
2462
+ }
2463
+
2464
+ return UINT2NUM(detect);
2465
+ }
2466
+
2467
+ /*
2468
+ * call-seq:
2469
+ * env.set_lk_max_locks(max) -> max
2470
+ *
2471
+ * Set the maximum number of locks in the environment
2472
+ */
2473
+ VALUE env_set_lk_max_locks(VALUE obj, VALUE vmax)
2474
+ {
2475
+ t_envh *eh;
2476
+ u_int32_t max;
2477
+ int rv;
2478
+
2479
+ max=FIX2UINT(vmax);
2480
+
2481
+ Data_Get_Struct(obj,t_envh,eh);
2482
+ if (!eh->env)
2483
+ raise(0, "env is closed");
2484
+ rv=eh->env->set_lk_max_locks(eh->env,max);
2485
+ if ( rv != 0 ) {
2486
+ raise_error(rv, "env_set_lk_max_locks: %s",db_strerror(rv));
2487
+ }
2488
+
2489
+ return vmax;
2490
+ }
2491
+
2492
+ /*
2493
+ * call-seq:
2494
+ * env.get_lk_max_locks -> max
2495
+ *
2496
+ * Get the maximum number of locks in the environment
2497
+ */
2498
+ VALUE env_get_lk_max_locks(VALUE obj)
2499
+ {
2500
+ t_envh *eh;
2501
+ u_int32_t max;
2502
+ int rv;
2503
+
2504
+ Data_Get_Struct(obj,t_envh,eh);
2505
+ if (!eh->env)
2506
+ raise(0, "env is closed");
2507
+ rv=eh->env->get_lk_max_locks(eh->env,&max);
2508
+ if ( rv != 0 ) {
2509
+ raise_error(rv, "env_get_lk_max_locks: %s",db_strerror(rv));
2510
+ }
2511
+
2512
+ return UINT2NUM(max);
2513
+ }
2514
+
2515
+ /*
2516
+ * call-seq:
2517
+ * env.set_lk_max_objects(max) -> max
2518
+ *
2519
+ * Set the maximum number of locks in the environment
2520
+ */
2521
+ VALUE env_set_lk_max_objects(VALUE obj, VALUE vmax)
2522
+ {
2523
+ t_envh *eh;
2524
+ u_int32_t max;
2525
+ int rv;
2526
+
2527
+ max=FIX2UINT(vmax);
2528
+
2529
+ Data_Get_Struct(obj,t_envh,eh);
2530
+ if (!eh->env)
2531
+ raise(0, "env is closed");
2532
+ rv=eh->env->set_lk_max_objects(eh->env,max);
2533
+ if ( rv != 0 ) {
2534
+ raise_error(rv, "env_set_lk_max_objects: %s",db_strerror(rv));
2535
+ }
2536
+
2537
+ return vmax;
2538
+ }
2539
+
2540
+ /*
2541
+ * call-seq:
2542
+ * env.get_lk_max_objects -> max
2543
+ *
2544
+ * Get the maximum number of locks in the environment
2545
+ */
2546
+ VALUE env_get_lk_max_objects(VALUE obj)
2547
+ {
2548
+ t_envh *eh;
2549
+ u_int32_t max;
2550
+ int rv;
2551
+
2552
+ Data_Get_Struct(obj,t_envh,eh);
2553
+ if (!eh->env)
2554
+ raise(0, "env is closed");
2555
+ rv=eh->env->get_lk_max_objects(eh->env,&max);
2556
+ if ( rv != 0 ) {
2557
+ raise_error(rv, "env_get_lk_max_objects: %s",db_strerror(rv));
2558
+ }
2559
+
2560
+ return UINT2NUM(max);
2561
+ }
2562
+
2563
+ VALUE env_report_stderr(VALUE obj)
2564
+ {
2565
+ t_envh *eh;
2566
+ u_int32_t max;
2567
+ int rv;
2568
+
2569
+ Data_Get_Struct(obj,t_envh,eh);
2570
+ if (!eh->env)
2571
+ raise(0, "env is closed");
2572
+ eh->env->set_errfile(eh->env,stderr);
2573
+
2574
+ return Qtrue;
2575
+ }
2576
+
2577
+ /*
2578
+ * call-seq:
2579
+ * env.set_data_dir(data_dir) -> data_dir
2580
+ *
2581
+ * set data_dir
2582
+ */
2583
+ VALUE env_set_data_dir(VALUE obj, VALUE vdata_dir)
2584
+ {
2585
+ t_envh *eh;
2586
+ const char *data_dir;
2587
+ int rv;
2588
+
2589
+ data_dir=StringValueCStr(vdata_dir);
2590
+
2591
+ Data_Get_Struct(obj,t_envh,eh);
2592
+ if (!eh->env)
2593
+ raise(0, "env is closed");
2594
+ rv=eh->env->set_data_dir(eh->env,data_dir);
2595
+ if ( rv != 0 ) {
2596
+ raise_error(rv, "env_set_data_dir: %s",db_strerror(rv));
2597
+ }
2598
+
2599
+ return vdata_dir;
2600
+ }
2601
+
2602
+ /*
2603
+ * call-seq:
2604
+ * env.get_data_dir -> [data_dir_1, data_dir_2, ...]
2605
+ *
2606
+ * get data_dir
2607
+ */
2608
+ VALUE env_get_data_dirs(VALUE obj)
2609
+ {
2610
+ t_envh *eh;
2611
+ const char **data_dirs;
2612
+ int rv;
2613
+ int ln;
2614
+
2615
+ Data_Get_Struct(obj,t_envh,eh);
2616
+ if (!eh->env)
2617
+ raise(0, "env is closed");
2618
+ rv=eh->env->get_data_dirs(eh->env,&data_dirs);
2619
+ if ( rv != 0 ) {
2620
+ raise_error(rv, "env_get_data_dir: %s",db_strerror(rv));
2621
+ }
2622
+
2623
+ ln = (sizeof (data_dirs))/sizeof(data_dirs[0]);
2624
+ VALUE rb_data_dirs = rb_ary_new2(ln);
2625
+ int i;
2626
+ for (i=0; i<ln; i++) {
2627
+ rb_ary_push(rb_data_dirs, rb_str_new2(data_dirs[i]));
2628
+ }
2629
+
2630
+ return rb_data_dirs;
2631
+ }
2632
+
2633
+ /*
2634
+ * call-seq:
2635
+ * env.set_lg_dir(lg_dir) -> lg_dir
2636
+ *
2637
+ * set lg_dir
2638
+ */
2639
+ VALUE env_set_lg_dir(VALUE obj, VALUE vlg_dir)
2640
+ {
2641
+ t_envh *eh;
2642
+ const char *lg_dir;
2643
+ int rv;
2644
+
2645
+ lg_dir=StringValueCStr(vlg_dir);
2646
+
2647
+ Data_Get_Struct(obj,t_envh,eh);
2648
+ if (!eh->env)
2649
+ raise(0, "env is closed");
2650
+ rv=eh->env->set_lg_dir(eh->env,lg_dir);
2651
+ if ( rv != 0 ) {
2652
+ raise_error(rv, "env_set_lg_dir: %s",db_strerror(rv));
2653
+ }
2654
+
2655
+ return vlg_dir;
2656
+ }
2657
+
2658
+ /*
2659
+ * call-seq:
2660
+ * env.get_lg_dir -> lg_dir
2661
+ *
2662
+ * get lg_dir
2663
+ */
2664
+ VALUE env_get_lg_dir(VALUE obj)
2665
+ {
2666
+ t_envh *eh;
2667
+ const char *lg_dir;
2668
+ int rv;
2669
+
2670
+ Data_Get_Struct(obj,t_envh,eh);
2671
+ if (!eh->env)
2672
+ raise(0, "env is closed");
2673
+ rv=eh->env->get_lg_dir(eh->env,&lg_dir);
2674
+ if ( rv != 0 ) {
2675
+ raise_error(rv, "env_get_lg_dir: %s",db_strerror(rv));
2676
+ }
2677
+
2678
+ return rb_str_new2(lg_dir);
2679
+ }
2680
+
2681
+ /*
2682
+ * call-seq:
2683
+ * env.set_tmp_dir(tmp_dir) -> tmp_dir
2684
+ *
2685
+ * set tmp_dir
2686
+ */
2687
+ VALUE env_set_tmp_dir(VALUE obj, VALUE vtmp_dir)
2688
+ {
2689
+ t_envh *eh;
2690
+ const char *tmp_dir;
2691
+ int rv;
2692
+
2693
+ tmp_dir=StringValueCStr(vtmp_dir);
2694
+
2695
+ Data_Get_Struct(obj,t_envh,eh);
2696
+ if (!eh->env)
2697
+ raise(0, "env is closed");
2698
+ rv=eh->env->set_tmp_dir(eh->env,tmp_dir);
2699
+ if ( rv != 0 ) {
2700
+ raise_error(rv, "env_set_tmp_dir: %s",db_strerror(rv));
2701
+ }
2702
+
2703
+ return vtmp_dir;
2704
+ }
2705
+
2706
+ /*
2707
+ * call-seq:
2708
+ * env.get_tmp_dir -> tmp_dir
2709
+ *
2710
+ * get tmp_dir
2711
+ */
2712
+ VALUE env_get_tmp_dir(VALUE obj)
2713
+ {
2714
+ t_envh *eh;
2715
+ const char *tmp_dir;
2716
+ int rv;
2717
+
2718
+ Data_Get_Struct(obj,t_envh,eh);
2719
+ if (!eh->env)
2720
+ raise(0, "env is closed");
2721
+ rv=eh->env->get_tmp_dir(eh->env,&tmp_dir);
2722
+ if ( rv != 0 ) {
2723
+ raise_error(rv, "env_get_tmp_dir: %s",db_strerror(rv));
2724
+ }
2725
+
2726
+ return rb_str_new2(tmp_dir);
2727
+ }
2728
+
2729
+ /*
2730
+ * call-seq:
2731
+ * env.get_home -> home
2732
+ *
2733
+ * get home
2734
+ */
2735
+ VALUE env_get_home(VALUE obj)
2736
+ {
2737
+ t_envh *eh;
2738
+ const char *home;
2739
+ int rv;
2740
+
2741
+ Data_Get_Struct(obj,t_envh,eh);
2742
+ if (!eh->env)
2743
+ raise(0, "env is closed");
2744
+ rv=eh->env->get_home(eh->env,&home);
2745
+ if ( rv != 0 ) {
2746
+ raise_error(rv, "env_get_home: %s",db_strerror(rv));
2747
+ }
2748
+
2749
+ return rb_str_new2(home);
2750
+ }
2751
+
2752
+ static void txn_finish(t_txnh *txn)
2753
+ {
2754
+ if ( RTEST(ruby_debug) )
2755
+ rb_warning("%s/%d %s 0x%x",__FILE__,__LINE__,"txn_finish",txn);
2756
+
2757
+ txn->txn=NULL;
2758
+ if (txn->env) {
2759
+ rb_ary_delete(txn->env->atxn,txn->self);
2760
+ txn->env=NULL;
2761
+ }
2762
+ }
2763
+
2764
+ /*
2765
+ * call-seq:
2766
+ * txn.commit(flags) -> true
2767
+ *
2768
+ * commit a transaction
2769
+ */
2770
+ VALUE txn_commit(VALUE obj, VALUE vflags)
2771
+ {
2772
+ t_txnh *txn=NULL;
2773
+ u_int32_t flags=0;
2774
+ int rv;
2775
+
2776
+ if ( ! NIL_P(vflags))
2777
+ flags=NUM2UINT(vflags);
2778
+
2779
+ Data_Get_Struct(obj,t_txnh,txn);
2780
+
2781
+ if (!txn->txn)
2782
+ return Qfalse;
2783
+
2784
+ rv=txn->txn->commit(txn->txn,flags);
2785
+ txn_finish(txn);
2786
+ if ( rv != 0 ) {
2787
+ raise_error(rv, "txn_commit: %s",db_strerror(rv));
2788
+ return Qnil;
2789
+ }
2790
+ return Qtrue;
2791
+ }
2792
+
2793
+ /*
2794
+ * call-seq:
2795
+ * txn.abort -> true
2796
+ *
2797
+ * abort a transaction
2798
+ */
2799
+ VALUE txn_abort(VALUE obj)
2800
+ {
2801
+ t_txnh *txn=NULL;
2802
+ int rv;
2803
+
2804
+ Data_Get_Struct(obj,t_txnh,txn);
2805
+
2806
+ if (!txn->txn)
2807
+ return Qfalse;
2808
+
2809
+ rv=txn->txn->abort(txn->txn);
2810
+ txn_finish(txn);
2811
+ if ( rv != 0 ) {
2812
+ raise_error(rv, "txn_abort: %s",db_strerror(rv));
2813
+ return Qnil;
2814
+ }
2815
+ return Qtrue;
2816
+ }
2817
+
2818
+ /*
2819
+ * call-seq:
2820
+ * txn.discard -> true
2821
+ *
2822
+ * discard a transaction. Since prepare is not yet supported,
2823
+ * I don't think this has much value.
2824
+ */
2825
+ VALUE txn_discard(VALUE obj)
2826
+ {
2827
+ t_txnh *txn=NULL;
2828
+ int rv;
2829
+
2830
+ Data_Get_Struct(obj,t_txnh,txn);
2831
+
2832
+ if (!txn->txn)
2833
+ raise_error(0,"txn is closed");
2834
+
2835
+ rv=txn->txn->discard(txn->txn,NOFLAGS);
2836
+ txn_finish(txn);
2837
+ if ( rv != 0 ) {
2838
+ raise_error(rv, "txn_abort: %s",db_strerror(rv));
2839
+ return Qnil;
2840
+ }
2841
+ return Qtrue;
2842
+ }
2843
+
2844
+ /*
2845
+ * call-seq:
2846
+ * txn.tid -> Fixnum
2847
+ *
2848
+ * return the transaction id, (named tid to not conflict with
2849
+ * ruby's id method)
2850
+ */
2851
+ VALUE txn_id(VALUE obj)
2852
+ {
2853
+ t_txnh *txn=NULL;
2854
+ int rv;
2855
+
2856
+ Data_Get_Struct(obj,t_txnh,txn);
2857
+ if (!txn->txn)
2858
+ raise_error(0,"txn is closed");
2859
+
2860
+ rv=txn->txn->id(txn->txn);
2861
+ return INT2FIX(rv);
2862
+ }
2863
+
2864
+ /*
2865
+ * call-seq:
2866
+ * tx.set_timeout(timeout,flags) -> true
2867
+ *
2868
+ * set transaction lock timeout
2869
+ */
2870
+ VALUE txn_set_timeout(VALUE obj, VALUE vtimeout, VALUE vflags)
2871
+ {
2872
+ t_txnh *txn=NULL;
2873
+ db_timeout_t timeout;
2874
+ u_int32_t flags=0;
2875
+ int rv;
2876
+
2877
+ if ( ! NIL_P(vflags))
2878
+ flags=NUM2UINT(vflags);
2879
+
2880
+ if ( ! FIXNUM_P(vtimeout) )
2881
+ raise_error(0,"timeout must be a fixed integer");
2882
+ timeout=FIX2UINT(vtimeout);
2883
+
2884
+ Data_Get_Struct(obj,t_txnh,txn);
2885
+
2886
+ if (!txn->txn)
2887
+ raise_error(0,"txn is closed");
2888
+
2889
+ rv=txn->txn->set_timeout(txn->txn,timeout,flags);
2890
+ if ( rv != 0 ) {
2891
+ raise_error(rv, "txn_set_timeout: %s",db_strerror(rv));
2892
+ return Qnil;
2893
+ }
2894
+ return Qtrue;
2895
+ }
2896
+
2897
+ /*
2898
+ * Document-class: Bdb
2899
+ *
2900
+ * Ruby library that wraps the Sleepycat Berkeley DB.
2901
+ *
2902
+ * Developed against 4.3/4.4. No support for prior versions.
2903
+ */
2904
+
2905
+ void Init_bdb() {
2906
+ fv_call=rb_intern("call");
2907
+ fv_uniq=rb_intern("uniq");
2908
+ fv_err_new=rb_intern("new");
2909
+ fv_err_code=rb_intern("@code");
2910
+ fv_err_msg=rb_intern("@message");
2911
+
2912
+ mBdb = rb_define_module("Bdb");
2913
+
2914
+ #include "bdb_aux._c"
2915
+
2916
+ cDb = rb_define_class_under(mBdb,"Db", rb_cObject);
2917
+ eDbError = rb_define_class_under(mBdb,"DbError",rb_eStandardError);
2918
+ rb_define_method(eDbError,"initialize",err_initialize,2);
2919
+ rb_define_method(eDbError,"code",err_code,0);
2920
+
2921
+ rb_define_const(cDb,"BTREE",INT2FIX((DBTYPE)(DB_BTREE)));
2922
+ rb_define_const(cDb,"HASH",INT2FIX((DBTYPE)(DB_HASH)));
2923
+ rb_define_const(cDb,"RECNO",INT2FIX((DBTYPE)(DB_RECNO)));
2924
+ rb_define_const(cDb,"QUEUE",INT2FIX((DBTYPE)(DB_QUEUE)));
2925
+ rb_define_const(cDb,"UNKNOWN",INT2FIX((DBTYPE)(DB_UNKNOWN)));
2926
+
2927
+ rb_define_alloc_func(cDb,db_alloc);
2928
+ rb_define_method(cDb,"initialize",db_initialize,0);
2929
+
2930
+ rb_define_method(cDb,"put",db_put,4);
2931
+ rb_define_method(cDb,"get",db_get,4);
2932
+ rb_define_method(cDb,"pget",db_pget,4);
2933
+ rb_define_method(cDb,"del",db_del,3);
2934
+ rb_define_method(cDb,"cursor",db_cursor,2);
2935
+ rb_define_method(cDb,"associate",db_associate,4);
2936
+ rb_define_method(cDb,"btree_compare=",db_btree_compare_set,1);
2937
+ rb_define_method(cDb,"flags=",db_flags_set,1);
2938
+ rb_define_method(cDb,"flags",db_flags_get,0);
2939
+ rb_define_method(cDb,"open",db_open,6);
2940
+ rb_define_method(cDb,"close",db_close,1);
2941
+ rb_define_method(cDb,"[]",db_aget,1);
2942
+ rb_define_method(cDb,"[]=",db_aset,2);
2943
+ rb_define_method(cDb,"join",db_join,2);
2944
+ rb_define_method(cDb,"get_byteswapped",db_get_byteswapped,0);
2945
+ rb_define_method(cDb,"get_type",db_get_type,0);
2946
+ rb_define_method(cDb,"remove",db_remove,3);
2947
+ rb_define_method(cDb,"key_range",db_key_range,3);
2948
+ rb_define_method(cDb,"rename",db_rename,4);
2949
+ rb_define_method(cDb,"pagesize",db_pagesize,0);
2950
+ rb_define_method(cDb,"pagesize=",db_pagesize_set,1);
2951
+ rb_define_method(cDb,"h_ffactor",db_h_ffactor,0);
2952
+ rb_define_method(cDb,"h_ffactor=",db_h_ffactor_set,1);
2953
+ rb_define_method(cDb,"h_nelem",db_h_nelem,0);
2954
+ rb_define_method(cDb,"h_nelem=",db_h_nelem_set,1);
2955
+ rb_define_method(cDb,"stat",db_stat,2);
2956
+ cDbStat = rb_define_class_under(cDb,"Stat",rb_cObject);
2957
+ rb_define_method(cDbStat,"[]",stat_aref,1);
2958
+
2959
+ rb_define_method(cDb,"sync",db_sync,0);
2960
+ rb_define_method(cDb,"truncate",db_truncate,1);
2961
+
2962
+ #if DB_VERSION_MINOR > 3
2963
+ rb_define_method(cDb,"compact",db_compact,5);
2964
+ #endif
2965
+
2966
+ cCursor = rb_define_class_under(cDb,"Cursor",rb_cObject);
2967
+ rb_define_method(cCursor,"get",dbc_get,3);
2968
+ rb_define_method(cCursor,"pget",dbc_pget,3);
2969
+ rb_define_method(cCursor,"put",dbc_put,3);
2970
+ rb_define_method(cCursor,"close",dbc_close,0);
2971
+ rb_define_method(cCursor,"del",dbc_del,0);
2972
+ rb_define_method(cCursor,"count",dbc_count,0);
2973
+
2974
+ cEnv = rb_define_class_under(mBdb,"Env",rb_cObject);
2975
+ rb_define_singleton_method(cEnv,"new",env_new,1);
2976
+ rb_define_method(cEnv,"open",env_open,3);
2977
+ rb_define_method(cEnv,"close",env_close,0);
2978
+ rb_define_method(cEnv,"db",env_db,0);
2979
+ rb_define_method(cEnv,"cachesize=",env_set_cachesize,1);
2980
+ rb_define_method(cEnv,"cachesize",env_get_cachesize,0);
2981
+ rb_define_method(cEnv,"flags",env_get_flags,0);
2982
+ rb_define_method(cEnv,"flags_on=",env_set_flags_on,1);
2983
+ rb_define_method(cEnv,"flags_off=",env_set_flags_off,1);
2984
+ rb_define_method(cEnv,"list_dbs",env_list_dbs,0);
2985
+ rb_define_method(cEnv,"txn_begin",env_txn_begin,2);
2986
+ rb_define_method(cEnv,"txn_checkpoint",env_txn_checkpoint,3);
2987
+ rb_define_method(cEnv,"txn_stat",env_txn_stat,1);
2988
+ rb_define_method(cEnv,"set_timeout",env_set_timeout,2);
2989
+ rb_define_method(cEnv,"get_timeout",env_get_timeout,1);
2990
+ rb_define_method(cEnv,"set_tx_max",env_set_tx_max,1);
2991
+ rb_define_method(cEnv,"mutex_get_max",env_mutex_get_max,0);
2992
+ rb_define_method(cEnv,"mutex_set_max",env_mutex_set_max,1);
2993
+ rb_define_method(cEnv,"get_tx_max",env_get_tx_max,0);
2994
+ rb_define_method(cEnv,"report_stderr",env_report_stderr,0);
2995
+ rb_define_method(cEnv,"set_lk_detect",env_set_lk_detect,1);
2996
+ rb_define_method(cEnv,"get_lk_detect",env_get_lk_detect,0);
2997
+ rb_define_method(cEnv,"set_lk_max_locks",env_set_lk_max_locks,1);
2998
+ rb_define_method(cEnv,"get_lk_max_locks",env_get_lk_max_locks,0);
2999
+ rb_define_method(cEnv,"set_lk_max_objects",env_set_lk_max_objects,1);
3000
+ rb_define_method(cEnv,"get_lk_max_objects",env_get_lk_max_objects,0);
3001
+ rb_define_method(cEnv,"set_shm_key",env_set_shm_key,1);
3002
+ rb_define_method(cEnv,"get_shm_key",env_get_shm_key,0);
3003
+
3004
+ rb_define_method(cEnv,"set_data_dir",env_set_data_dir,1);
3005
+ rb_define_method(cEnv,"get_data_dirs",env_get_data_dirs,0);
3006
+ rb_define_method(cEnv,"set_lg_dir",env_set_lg_dir,1);
3007
+ rb_define_method(cEnv,"get_lg_dir",env_get_lg_dir,0);
3008
+ rb_define_method(cEnv,"set_tmp_dir",env_set_tmp_dir,1);
3009
+ rb_define_method(cEnv,"get_tmp_dir",env_get_tmp_dir,0);
3010
+ rb_define_method(cEnv,"get_home",env_get_home,0);
3011
+
3012
+ cTxnStat = rb_define_class_under(mBdb,"TxnStat",rb_cObject);
3013
+ rb_define_method(cTxnStat,"[]",stat_aref,1);
3014
+
3015
+ cTxnStatActive =
3016
+ rb_define_class_under(cTxnStat,"Active",rb_cObject);
3017
+ rb_define_method(cTxnStatActive,"[]",stat_aref,1);
3018
+
3019
+ cTxn = rb_define_class_under(mBdb,"Txn",rb_cObject);
3020
+ rb_define_method(cTxn,"commit",txn_commit,1);
3021
+ rb_define_method(cTxn,"abort",txn_abort,0);
3022
+ rb_define_method(cTxn,"discard",txn_discard,0);
3023
+ rb_define_method(cTxn,"tid",txn_id,0);
3024
+ rb_define_method(cTxn,"set_timeout",txn_set_timeout,2);
3025
+ }