dk-bdb 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/bdb.c ADDED
@@ -0,0 +1,3421 @@
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
+ #define EXCEPTIONS_CREATE \
36
+ eDbE_create(BUFFER_SMALL, BufferSmall)\
37
+ eDbE_create(LOCK_DEADLOCK, LockDeadlock)\
38
+ eDbE_create(LOCK_NOTGRANTED, LockNotgranted)\
39
+ eDbE_create(REP_HANDLE_DEAD, RepHandleDead)\
40
+ eDbE_create(REP_LEASE_EXPIRED, RepLeaseExpired)\
41
+ eDbE_create(REP_LOCKOUT, RepLockout)\
42
+ eDbE_create(SECONDARY_BAD, SecondaryBad) \
43
+ eDbE_create(FOREIGN_CONFLICT, ForeignConflict) \
44
+ eDbE_create(OLD_VERSION, OldVersion) \
45
+ eDbE_create(KEYEXIST, KeyExist) \
46
+ eDbE_create(KEYEMPTY, KeyEmpty) \
47
+ eDbE_create(RUNRECOVERY, RunRecovery) \
48
+ eDbE_create(VERSION_MISMATCH, VersionMismatch)
49
+
50
+ #define eDbE_create(n,c) VALUE eDbE_##c;
51
+ EXCEPTIONS_CREATE
52
+
53
+ /*
54
+ * Document-class: Bdb::DbError
55
+ *
56
+ * Errors generated by methods under the Bdb hierarchy will be
57
+ * of this class unless Ruby itself raises the error.
58
+ *
59
+ */
60
+
61
+ static void
62
+ #ifdef HAVE_STDARG_PROTOTYPES
63
+ raise_error(int code, const char *fmt, ...)
64
+ #else
65
+ raise_error(code,fmt,va_alist)
66
+ int code;
67
+ const char *fmt;
68
+ va_dcl
69
+ #endif
70
+ {
71
+ va_list args;
72
+ char buf[1024];
73
+ VALUE exc;
74
+ VALUE argv[2];
75
+
76
+ va_init_list(args,fmt);
77
+ vsnprintf(buf,1024,fmt,args);
78
+ va_end(args);
79
+
80
+ argv[0]=rb_str_new2(buf);
81
+ argv[1]=INT2NUM(code);
82
+ VALUE cl;
83
+ switch( code) {
84
+ #define eDbE_create(n,c) case DB_##n: cl = eDbE_##c; break;
85
+ EXCEPTIONS_CREATE
86
+ default: cl = eDbError; break;
87
+ }
88
+
89
+ exc=rb_class_new_instance(2,argv,cl);
90
+ rb_exc_raise(exc);
91
+ }
92
+
93
+ /*
94
+ * An error can only be generated internally
95
+ */
96
+ VALUE err_initialize(VALUE obj, VALUE message, VALUE code)
97
+ {
98
+ VALUE args[1];
99
+ args[0]=message;
100
+ rb_call_super(1,args);
101
+ return rb_ivar_set(obj,fv_err_code,code);
102
+ }
103
+
104
+ /*
105
+ * call-seq:
106
+ * err.code() -> Bdb error code integer
107
+ *
108
+ */
109
+ VALUE err_code(VALUE obj)
110
+ {
111
+ return rb_ivar_get(obj,fv_err_code);
112
+ }
113
+
114
+ static void db_free(t_dbh *dbh)
115
+ {
116
+ #ifdef DEBUG_DB
117
+ if ( RTEST(ruby_debug) )
118
+ fprintf(stderr,"%s/%d %s 0x%x\n",__FILE__,__LINE__,"db_free cleanup!",dbh);
119
+ #endif
120
+
121
+ if (dbh) {
122
+ if (dbh->db) {
123
+ if (dbh->db_opened == 1)
124
+ dbh->db->close(dbh->db,NOFLAGS);
125
+ if ( RTEST(ruby_debug) && dbh->filename[0] != '\0')
126
+ fprintf(stderr,"%s/%d %s %p %s\n",__FILE__,__LINE__,
127
+ "db_free database was still open!",(void*)dbh->db,dbh->filename);
128
+ dbh->db=NULL;
129
+ }
130
+ free(dbh);
131
+ }
132
+ }
133
+
134
+ static void db_mark(t_dbh *dbh)
135
+ {
136
+ if ( dbh == NULL ) return;
137
+ if ( ! NIL_P(dbh->aproc) )
138
+ rb_gc_mark(dbh->aproc);
139
+ if ( dbh->env )
140
+ rb_gc_mark(dbh->env->self);
141
+ if ( ! NIL_P(dbh->adbc) )
142
+ rb_gc_mark(dbh->adbc);
143
+ }
144
+
145
+ static void dbc_mark(t_dbch *dbch)
146
+ {
147
+ if (dbch->db)
148
+ rb_gc_mark(dbch->db->self);
149
+ }
150
+ static void dbc_free(void *p)
151
+ {
152
+ t_dbch *dbch;
153
+ dbch=(t_dbch *)p;
154
+
155
+ #ifdef DEBUG_DB
156
+ if ( RTEST(ruby_debug) )
157
+ fprintf(stderr,"%s/%d %s 0x%x\n",__FILE__,__LINE__,
158
+ "dbc_free cleanup!",p);
159
+ #endif
160
+
161
+ if ( dbch ) {
162
+ if ( dbch->dbc ) {
163
+ dbch->dbc->c_close(dbch->dbc);
164
+ if ( RTEST(ruby_debug) )
165
+ fprintf(stderr,"%s/%d %s %p %s\n",__FILE__,__LINE__,
166
+ "dbc_free cursor was still open!",p,dbch->filename);
167
+ }
168
+ free(p);
169
+ }
170
+ }
171
+
172
+ VALUE
173
+ db_alloc(VALUE klass)
174
+ {
175
+ return Data_Wrap_Struct(klass,db_mark,db_free,0);
176
+ }
177
+
178
+ VALUE db_init_aux(VALUE obj,t_envh * eh)
179
+ {
180
+ DB *db;
181
+ t_dbh *dbh;
182
+ int rv;
183
+
184
+ /* This excludes possible use of X/Open Transaction Mgr */
185
+ rv = db_create(&db,(eh)?eh->env:NULL,NOFLAGS);
186
+ if (rv != 0) {
187
+ raise_error(rv, "db_new failure: %s",db_strerror(rv));
188
+ }
189
+
190
+ #ifdef DEBUG_DB
191
+ db->set_errfile(db,stderr);
192
+ #endif
193
+
194
+ dbh=ALLOC(t_dbh);
195
+ if (DATA_PTR(obj)) {
196
+ /* if called from env_db, the data ptr has not been allocated,
197
+ * was freeing 0x0 */
198
+ db_free(DATA_PTR(obj));
199
+ }
200
+ DATA_PTR(obj)=dbh;
201
+ dbh->db=db;
202
+ dbh->self=obj;
203
+ dbh->env=eh;
204
+ dbh->aproc=Qnil;
205
+ dbh->sproc=Qnil;
206
+ memset(&(dbh->filename),0,FNLEN+1);
207
+
208
+ dbh->adbc=Qnil;
209
+
210
+ if (dbh->env) {
211
+ #ifdef DEBUG_DB
212
+ fprintf(stderr,"Adding db to env 0x%x 0x%x\n",obj,dbh);
213
+ #endif
214
+ rb_ary_push(dbh->env->adb,obj);
215
+ }
216
+
217
+ return obj;
218
+ }
219
+
220
+ /*
221
+ * Document-class: Bdb::Db
222
+ *
223
+ */
224
+
225
+ VALUE db_initialize(VALUE obj)
226
+ {
227
+ return db_init_aux(obj,NULL);
228
+ }
229
+
230
+ /*
231
+ * call-seq:
232
+ * db.open(txn_object,disk_file,logical_db,db_type,flags,mode) -> value
233
+ *
234
+ * open a database. disk file is file path. logical_db is
235
+ * a named database within that file, which will be created under
236
+ * conditions noted by DB.
237
+ *
238
+ * db_type is one of the constants:
239
+ * Bdb::DB::BTREE
240
+ * Bdb::DB::HASH
241
+ * Bdb::DB::RECNO
242
+ * Bdb::DB::QUEUE
243
+ * Bdb::DB::UNKNOWN
244
+ *
245
+ * unknown will open an already existing db in the mode created
246
+ */
247
+ VALUE db_open(VALUE obj, VALUE vtxn, VALUE vdisk_file,
248
+ VALUE vlogical_db,
249
+ VALUE vdbtype, VALUE vflags, VALUE vmode)
250
+ {
251
+ t_dbh *dbh;
252
+ int rv;
253
+ t_txnh *txn=NOTXN;
254
+ u_int32_t flags=0;
255
+ DBTYPE dbtype=DB_UNKNOWN;
256
+ char *logical_db=NULL;
257
+ //long len;
258
+ int mode=0;
259
+
260
+ if ( ! NIL_P(vflags) )
261
+ flags=NUM2UINT(vflags);
262
+
263
+ if ( ! NIL_P(vtxn) ) {
264
+ Data_Get_Struct(vtxn,t_txnh,txn);
265
+ if (!txn->txn)
266
+ raise(0, "txn is closed");
267
+ }
268
+
269
+ if ( TYPE(vlogical_db)==T_STRING && RSTRING_LEN(vlogical_db) > 0 )
270
+ logical_db=StringValueCStr(vlogical_db);
271
+
272
+ if ( FIXNUM_P(vdbtype) ) {
273
+ dbtype=NUM2INT(vdbtype);
274
+ if ( dbtype < DB_BTREE || dbtype > DB_UNKNOWN ) {
275
+ raise_error(0,"db_open Bad access type: %d",dbtype);
276
+ return Qnil;
277
+ }
278
+ }
279
+
280
+ if ( TYPE(vdisk_file)!=T_STRING || RSTRING_LEN(vdisk_file) < 1 ) {
281
+ raise_error(0,"db_open Bad disk file name");
282
+ return Qnil;
283
+ }
284
+
285
+ if ( ! NIL_P(vmode) )
286
+ mode=NUM2INT(vmode);
287
+
288
+ Data_Get_Struct(obj,t_dbh,dbh);
289
+ if ( ! NIL_P(dbh->adbc) )
290
+ raise_error(0,"db handle already opened");
291
+
292
+ dbh->db->app_private=dbh;
293
+ rv = dbh->db->open(dbh->db,txn?txn->txn:NULL,
294
+ StringValueCStr(vdisk_file),
295
+ logical_db,
296
+ dbtype,flags,mode);
297
+ if (rv != 0) {
298
+ raise_error(rv,"db_open failure: %s(%d)",db_strerror(rv),rv);
299
+ }
300
+ filename_copy(dbh->filename,vdisk_file)
301
+ dbh->adbc=rb_ary_new();
302
+ dbh->db_opened = 1;
303
+ return obj;
304
+ }
305
+
306
+ /**
307
+ * call-seq:
308
+ * db.set_re_len( db, re_len)
309
+ *
310
+ * Set record-length
311
+ */
312
+ VALUE db_set_re_len(VALUE obj, VALUE re_len) {
313
+ int rv;
314
+ t_dbh *dbh;
315
+ Data_Get_Struct(obj,t_dbh,dbh);
316
+ if (!dbh->db)
317
+ raise_error(0,"db isn't created");
318
+ rv = dbh->db->set_re_len(dbh->db,NUM2UINT(re_len));
319
+ if ( rv != 0 )
320
+ raise_error(rv, "set_re_len failure: %s",db_strerror(rv));
321
+ return re_len;
322
+ }
323
+
324
+ VALUE db_get_re_len( VALUE obj) {
325
+ u_int32_t re_len;
326
+ t_dbh *dbh;
327
+ Data_Get_Struct(obj,t_dbh,dbh);
328
+ if (!dbh->db)
329
+ raise_error(0,"db isn't created");
330
+ int rv = dbh->db->get_re_len(dbh->db,&re_len);
331
+ if ( rv != 0 )
332
+ raise_error(rv, "db_get_re_len failure: %s",db_strerror(rv));
333
+ return UINT2NUM(re_len);
334
+ }
335
+
336
+ /*
337
+ * call-seq:
338
+ * db.flags=value
339
+ *
340
+ * set database flags based on DB constants.
341
+ * see http://www.sleepycat.com/docs/api_c/db_set_flags.html
342
+ *
343
+ */
344
+ VALUE db_flags_set(VALUE obj, VALUE vflags)
345
+ {
346
+ t_dbh *dbh;
347
+ int rv;
348
+ u_int32_t flags;
349
+
350
+ flags=NUM2UINT(vflags);
351
+ Data_Get_Struct(obj,t_dbh,dbh);
352
+ if (!dbh->db)
353
+ raise_error(0,"db is closed");
354
+
355
+ rv = dbh->db->set_flags(dbh->db,flags);
356
+ if ( rv != 0 ) {
357
+ raise_error(rv, "db_flag_set failure: %s",db_strerror(rv));
358
+ }
359
+ return vflags;
360
+ }
361
+
362
+ /*
363
+ * call-seq:
364
+ * db.flags -> value
365
+ *
366
+ * get database flags.
367
+ * see http://www.sleepycat.com/docs/api_c/db_get_flags.html
368
+ *
369
+ */
370
+ VALUE db_flags_get(VALUE obj)
371
+ {
372
+ t_dbh *dbh;
373
+ int rv;
374
+ u_int32_t flags;
375
+
376
+ Data_Get_Struct(obj,t_dbh,dbh);
377
+ if (!dbh->db)
378
+ raise_error(0,"db is closed");
379
+
380
+ rv = dbh->db->get_flags(dbh->db,&flags);
381
+ if ( rv != 0 ) {
382
+ raise_error(rv, "db_flag_get failure: %s",db_strerror(rv));
383
+ }
384
+ return INT2NUM(flags);
385
+ }
386
+
387
+ /*
388
+ * call-seq:
389
+ * db.pagesize=value
390
+ *
391
+ * set database flags based on DB constants.
392
+ * see http://www.sleepycat.com/docs/api_c/db_set_flags.html
393
+ *
394
+ */
395
+ VALUE db_pagesize_set(VALUE obj, VALUE vpagesize)
396
+ {
397
+ t_dbh *dbh;
398
+ int rv;
399
+ u_int32_t pagesize;
400
+
401
+ pagesize=NUM2INT(vpagesize);
402
+ Data_Get_Struct(obj,t_dbh,dbh);
403
+ if (!dbh->db)
404
+ raise_error(0,"db is closed");
405
+ rv = dbh->db->set_pagesize(dbh->db,pagesize);
406
+ if ( rv != 0 ) {
407
+ raise_error(rv, "db_pagesize_set failure: %s",db_strerror(rv));
408
+ }
409
+ return vpagesize;
410
+ }
411
+
412
+ /*
413
+ * call-seq:
414
+ * db.pagesize
415
+ *
416
+ * set database flags based on DB constants.
417
+ * see http://www.sleepycat.com/docs/api_c/db_set_flags.html
418
+ *
419
+ */
420
+ VALUE db_pagesize(VALUE obj)
421
+ {
422
+ t_dbh *dbh;
423
+ int rv;
424
+ u_int32_t pagesize;
425
+
426
+ Data_Get_Struct(obj,t_dbh,dbh);
427
+ if (!dbh->db)
428
+ raise_error(0,"db is closed");
429
+ rv = dbh->db->get_pagesize(dbh->db,&pagesize);
430
+ if ( rv != 0 ) {
431
+ raise_error(rv, "db_pagesize_get failure: %s",db_strerror(rv));
432
+ }
433
+ return INT2NUM(pagesize);
434
+ }
435
+
436
+ /*
437
+ * call-seq:
438
+ * db.h_ffactor=value
439
+ *
440
+ * get hash db fill factor
441
+ * formula:
442
+ * (pagesize - 32) / (average_key_size + average_data_size + 8)
443
+ *
444
+ */
445
+ VALUE db_h_ffactor_set(VALUE obj, VALUE vint)
446
+ {
447
+ t_dbh *dbh;
448
+ int rv;
449
+ u_int32_t cint;
450
+
451
+ cint=NUM2INT(vint);
452
+ Data_Get_Struct(obj,t_dbh,dbh);
453
+ if (!dbh->db)
454
+ raise_error(0,"db is closed");
455
+ rv = dbh->db->set_h_ffactor(dbh->db,cint);
456
+ if ( rv != 0 ) {
457
+ raise_error(rv, "db_h_ffactor_set failure: %s",db_strerror(rv));
458
+ }
459
+ return vint;
460
+ }
461
+
462
+ /*
463
+ * call-seq:
464
+ * db.h_ffactor
465
+ *
466
+ * get hash db fill factor
467
+ * formula:
468
+ * (pagesize - 32) / (average_key_size + average_data_size + 8)
469
+ * see http://www.sleepycat.com/docs/api_c/db_set_flags.html
470
+ *
471
+ */
472
+ VALUE db_h_ffactor(VALUE obj)
473
+ {
474
+ t_dbh *dbh;
475
+ int rv;
476
+ u_int32_t cint;
477
+
478
+ Data_Get_Struct(obj,t_dbh,dbh);
479
+ if (!dbh->db)
480
+ raise_error(0,"db is closed");
481
+ rv = dbh->db->get_h_ffactor(dbh->db,&cint);
482
+ if ( rv != 0 ) {
483
+ raise_error(rv, "db_h_ffactor failure: %s",db_strerror(rv));
484
+ }
485
+ return INT2NUM(cint);
486
+ }
487
+ /*
488
+ * call-seq:
489
+ * db.h_nelem=value
490
+ *
491
+ * set estimate number of elements in hash table
492
+ * see http://www.sleepycat.com/docs/api_c/db_set_flags.html
493
+ *
494
+ */
495
+ VALUE db_h_nelem_set(VALUE obj, VALUE vint)
496
+ {
497
+ t_dbh *dbh;
498
+ int rv;
499
+ u_int32_t cint;
500
+
501
+ cint=NUM2INT(vint);
502
+ Data_Get_Struct(obj,t_dbh,dbh);
503
+ if (!dbh->db)
504
+ raise_error(0,"db is closed");
505
+ rv = dbh->db->set_h_nelem(dbh->db,cint);
506
+ if ( rv != 0 ) {
507
+ raise_error(rv, "db_h_nelem_set failure: %s",db_strerror(rv));
508
+ }
509
+ return vint;
510
+ }
511
+
512
+ /*
513
+ * call-seq:
514
+ * db.h_nelem
515
+ *
516
+ * get estimate number of element in the hash table
517
+ * see http://www.sleepycat.com/docs/api_c/db_set_flags.html
518
+ *
519
+ */
520
+ VALUE db_h_nelem(VALUE obj)
521
+ {
522
+ t_dbh *dbh;
523
+ int rv;
524
+ u_int32_t nelem;
525
+
526
+ Data_Get_Struct(obj,t_dbh,dbh);
527
+ if (!dbh->db)
528
+ raise_error(0,"db is closed");
529
+ rv = dbh->db->get_h_nelem(dbh->db,&nelem);
530
+ if ( rv != 0 ) {
531
+ raise_error(rv, "db_h_nelem failure: %s",db_strerror(rv));
532
+ }
533
+ return INT2NUM(nelem);
534
+ }
535
+
536
+ VALUE dbc_close(VALUE);
537
+
538
+ /* call-seq:
539
+ * db.close(flags) -> value
540
+ *
541
+ * close a database handle. Will close open cursors.
542
+ */
543
+ VALUE db_close(VALUE obj, VALUE vflags)
544
+ {
545
+ t_dbh *dbh;
546
+ int rv;
547
+ u_int32_t flags;
548
+ VALUE cur;
549
+
550
+ flags=NUM2UINT(vflags);
551
+ Data_Get_Struct(obj,t_dbh,dbh);
552
+ if ( dbh->db==NULL )
553
+ return Qnil;
554
+
555
+ if (! NIL_P(dbh->adbc) && RARRAY_LEN(dbh->adbc) > 0 ) {
556
+ rb_warning("%s/%d %s",__FILE__,__LINE__,
557
+ "cursor handles still open");
558
+ while ( (cur=rb_ary_pop(dbh->adbc)) != Qnil ) {
559
+ dbc_close(cur);
560
+ }
561
+ }
562
+
563
+ if ( RTEST(ruby_debug) )
564
+ rb_warning("%s/%d %s 0x%p %s",__FILE__,__LINE__,"db_close!", (void*)dbh,
565
+ (dbh->filename==NULL||*(dbh->filename)=='0') ? (char*)"unknown" : dbh->filename);
566
+
567
+ rv = dbh->db->close(dbh->db,flags);
568
+ dbh->db=NULL;
569
+ dbh->aproc=Qnil;
570
+ dbh->sproc=Qnil;
571
+ if ( dbh->env ) {
572
+ if ( RTEST(ruby_debug) )
573
+ rb_warning("%s/%d %s 0x%p",__FILE__,__LINE__,"db_close! removing",(void*)obj);
574
+ rb_ary_delete(dbh->env->adb,obj);
575
+ dbh->env = NULL;
576
+ }
577
+ if ( rv != 0 ) {
578
+ raise_error(rv, "db_close failure: %s",db_strerror(rv));
579
+ }
580
+ dbh->db_opened = 0;
581
+ return obj;
582
+ }
583
+
584
+ /*
585
+ * call-seq:
586
+ * db.put(txn,key,data,flags) -> self
587
+ *
588
+ * put a key/data pair into the database. returns db. Will
589
+ * raise an error on DB_KEYEXIST but error.code will indicate
590
+ * so it can be easily caught.
591
+ */
592
+ VALUE db_put(VALUE obj, VALUE vtxn, VALUE vkey, VALUE vdata, VALUE vflags)
593
+ {
594
+ t_dbh *dbh;
595
+ int rv;
596
+ u_int32_t flags=0;
597
+ DBT key,data;
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
+ Data_Get_Struct(obj,t_dbh,dbh);
613
+ if (!dbh->db)
614
+ raise_error(0,"db is closed");
615
+
616
+ key.data = RSTRING_PTR(vkey);
617
+ key.size = RSTRING_LEN(vkey);
618
+ key.flags = LMEMFLAG;
619
+
620
+ StringValue(vdata);
621
+ data.data = RSTRING_PTR(vdata);
622
+ data.size = RSTRING_LEN(vdata);
623
+ data.flags = LMEMFLAG;
624
+
625
+ rv = dbh->db->put(dbh->db,txn?txn->txn:NULL,&key,&data,flags);
626
+ /*
627
+ if (rv == DB_KEYEXIST)
628
+ return Qnil;
629
+ */
630
+ if (rv != 0) {
631
+ raise_error(rv, "db_put fails: %s",db_strerror(rv));
632
+ }
633
+
634
+ if ( flags & DB_APPEND == DB_APPEND ) {
635
+ VALUE str = rb_str_new(key.data,key.size);
636
+ if (key.data) free(key.data);
637
+ return str;
638
+ }
639
+
640
+ return obj;
641
+ }
642
+
643
+ /*
644
+ * call-seq:
645
+ * db.get(txn,key,data,flags) -> String(data)
646
+ *
647
+ * get a key/data pair from database. data as a string.
648
+ *
649
+ */
650
+
651
+ VALUE db_get(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;
657
+ VALUE str;
658
+ t_txnh *txn=NULL;
659
+
660
+ memset(&key,0,sizeof(DBT));
661
+ memset(&data,0,sizeof(DBT));
662
+
663
+ if ( ! NIL_P(vtxn) ) {
664
+ Data_Get_Struct(vtxn,t_txnh,txn);
665
+ if (!txn->txn)
666
+ raise(0, "txn is closed");
667
+ }
668
+
669
+ if ( ! NIL_P(vflags) ) {
670
+ flags=NUM2UINT(vflags);
671
+ }
672
+
673
+ Data_Get_Struct(obj,t_dbh,dbh);
674
+ if (!dbh->db)
675
+ raise_error(0,"db is closed");
676
+
677
+ StringValue(vkey);
678
+
679
+ key.data = RSTRING_PTR(vkey);
680
+ key.size = RSTRING_LEN(vkey);
681
+ key.flags = LMEMFLAG;
682
+
683
+ if ( ! NIL_P(vdata) ) {
684
+ StringValue(vdata);
685
+ data.data = RSTRING_PTR(vdata);
686
+ data.size = RSTRING_LEN(vdata);
687
+ }
688
+ data.flags = DB_DBT_MALLOC;
689
+
690
+ rv = dbh->db->get(dbh->db,txn?txn->txn:NULL,&key,&data,flags);
691
+ if ( rv == 0 ) {
692
+ str = rb_str_new(data.data,data.size);
693
+ if (data.data) free(data.data);
694
+ return str;
695
+ } else if (rv == DB_NOTFOUND) {
696
+ return Qnil;
697
+ } else {
698
+ raise_error(rv, "db_get failure: %s",db_strerror(rv));
699
+ }
700
+ return Qnil;
701
+ }
702
+
703
+ /*
704
+ * call-seq:
705
+ * db.pget(txn,key,data,flags) -> [pkey,data]
706
+ *
707
+ * get a key/data pair from database using a secondary index.
708
+ * returns an array with a primary key and the data element.
709
+ *
710
+ */
711
+ VALUE db_pget(VALUE obj, VALUE vtxn, VALUE vkey, VALUE vdata, VALUE vflags)
712
+ {
713
+ t_dbh *dbh;
714
+ int rv;
715
+ u_int32_t flags=0;
716
+ DBT key,data,pkey;
717
+ //VALUE str;
718
+ t_txnh *txn=NULL;
719
+
720
+ memset(&key,0,sizeof(DBT));
721
+ memset(&data,0,sizeof(DBT));
722
+ memset(&pkey,0,sizeof(DBT));
723
+
724
+ if ( ! NIL_P(vtxn) ) {
725
+ Data_Get_Struct(vtxn,t_txnh,txn);
726
+ if (!txn->txn)
727
+ raise(0, "txn is closed");
728
+ }
729
+
730
+ if ( ! NIL_P(vflags) ) {
731
+ flags=NUM2UINT(vflags);
732
+ }
733
+
734
+ Data_Get_Struct(obj,t_dbh,dbh);
735
+ if (!dbh->db)
736
+ raise(0, "db is closed");
737
+
738
+ StringValue(vkey);
739
+
740
+ key.data = RSTRING_PTR(vkey);
741
+ key.size = RSTRING_LEN(vkey);
742
+ key.flags = LMEMFLAG;
743
+
744
+ if ( ! NIL_P(vdata) ) {
745
+ StringValue(vdata);
746
+ data.data = RSTRING_PTR(vdata);
747
+ data.size = RSTRING_LEN(vdata);
748
+ data.flags = LMEMFLAG;
749
+ }
750
+
751
+ rv = dbh->db->pget(dbh->db,txn?txn->txn:NULL,&key,&pkey,&data,flags);
752
+ if ( rv == 0 ) {
753
+ return
754
+ rb_ary_new3(2,
755
+ rb_str_new(pkey.data,pkey.size),
756
+ rb_str_new(data.data,data.size));
757
+
758
+ } else if (rv == DB_NOTFOUND) {
759
+ return Qnil;
760
+ } else {
761
+ raise_error(rv, "db_pget failure: %s",db_strerror(rv));
762
+ }
763
+ return Qnil;
764
+ }
765
+
766
+ /*
767
+ * call-seq:
768
+ * db[key] -> data
769
+ *
770
+ * array ref style data retrieval
771
+ *
772
+ */
773
+ VALUE db_aget(VALUE obj, VALUE vkey)
774
+ {
775
+ return db_get(obj,Qnil,vkey,Qnil,Qnil);
776
+ }
777
+
778
+ /*
779
+ * call-seq:
780
+ * db[key]=data
781
+ *
782
+ * array ref style data storage
783
+ */
784
+ VALUE db_aset(VALUE obj, VALUE vkey, VALUE vdata)
785
+ {
786
+ return db_put(obj,Qnil,vkey,vdata,Qnil);
787
+ }
788
+
789
+ /*
790
+ * call-seq:
791
+ * db.join([cursors],flags) -> join_cursor
792
+ *
793
+ * create a join cursor from an array of cursors.
794
+ * The input cursors will usually be set_range and, if duplicate
795
+ * data items are allowed the should be DUP_SORT or the performance
796
+ * will be abysmal.
797
+ */
798
+ VALUE db_join(VALUE obj, VALUE vacurs, VALUE vflags)
799
+ {
800
+ t_dbh *dbh;
801
+ t_dbch *dbch;
802
+ u_int32_t flags;
803
+ DBC **curs;
804
+ int i,rv;
805
+ VALUE jcurs;
806
+
807
+ flags=NUM2UINT(vflags);
808
+ Data_Get_Struct(obj,t_dbh,dbh);
809
+ if (!dbh->db)
810
+ raise(0, "db is closed");
811
+
812
+ curs = ALLOCA_N(DBC *,RARRAY_LEN(vacurs));
813
+ for (i=0; i<RARRAY_LEN(vacurs); i++) {
814
+ Data_Get_Struct(RARRAY_PTR(vacurs)[i],t_dbch,dbch);
815
+ /* cursor is closed? */
816
+ curs[i]=dbch->dbc;
817
+ }
818
+ curs[i]=NULL;
819
+ jcurs=Data_Make_Struct(cCursor,t_dbch,dbc_mark,dbc_free,dbch);
820
+ rv = dbh->db->join(dbh->db,curs,&(dbch->dbc),flags);
821
+ if (rv) {
822
+ raise_error(rv, "db_join: %s",db_strerror(rv));
823
+ }
824
+ dbch->db=dbh;
825
+ rb_ary_push(dbch->db->adbc,jcurs);
826
+ rb_obj_call_init(jcurs,0,NULL);
827
+ return jcurs;
828
+ }
829
+
830
+ #if DB_VERSION_MINOR > 3
831
+ /*
832
+ * call-seq:
833
+ * db.compact(txn,start_key,stop_key,compact_opts,flags) -> end_key
834
+ *
835
+ * compact the database (4.4 an up). start and stop keys limit the
836
+ * range of compaction in BTREE types. compact_opts is currently
837
+ * ignored. Call returns the last key compacted (could be fed into
838
+ * a subsequent call as the start_key).
839
+ *
840
+ */
841
+ VALUE db_compact(VALUE obj, VALUE vtxn, VALUE vstart_key,
842
+ VALUE vstop_key, VALUE db_compact,
843
+ VALUE vflags)
844
+ {
845
+ t_dbh *dbh;
846
+ u_int32_t flags;
847
+ t_txnh *txn=NULL;
848
+ DBT start_key, stop_key, end_key;
849
+ int rv;
850
+
851
+ flags=NUM2UINT(vflags);
852
+ Data_Get_Struct(obj,t_dbh,dbh);
853
+ if (!dbh->db)
854
+ raise(0, "db is closed");
855
+
856
+ memset(&start_key,0,sizeof(DBT));
857
+ memset(&stop_key,0,sizeof(DBT));
858
+ memset(&end_key,0,sizeof(DBT));
859
+
860
+ if ( ! NIL_P(vstart_key) ) {
861
+ StringValue(vstart_key);
862
+ start_key.data=RSTRING_PTR(vstart_key);
863
+ start_key.size=RSTRING_LEN(vstart_key);
864
+ start_key.flags= LMEMFLAG;
865
+ }
866
+ if ( ! NIL_P(vstop_key) ) {
867
+ StringValue(vstop_key);
868
+ stop_key.data=RSTRING_PTR(vstop_key);
869
+ stop_key.size=RSTRING_LEN(vstop_key);
870
+ stop_key.flags= LMEMFLAG;
871
+ }
872
+ if ( ! NIL_P(vtxn) ) {
873
+ Data_Get_Struct(vtxn,t_txnh,txn);
874
+ if (!txn->txn)
875
+ raise(0, "txn is closed");
876
+ }
877
+
878
+ rv=dbh->db->compact(dbh->db,txn?txn->txn:NULL,
879
+ &start_key,
880
+ &stop_key,
881
+ NULL,
882
+ flags,
883
+ &end_key);
884
+ if (rv)
885
+ raise_error(rv,"db_compact failure: %s",db_strerror(rv));
886
+
887
+ return rb_str_new(end_key.data,end_key.size);
888
+
889
+ }
890
+ #endif
891
+
892
+ /*
893
+ * call-seq:
894
+ * db.get_byteswapped -> true/false
895
+ *
896
+ * true if database is running in swapped mode. This happens when
897
+ * the db is created on a machine with a different endian.
898
+ */
899
+ VALUE db_get_byteswapped(VALUE obj)
900
+ {
901
+ t_dbh *dbh;
902
+ int rv;
903
+ int is_swapped;
904
+
905
+ Data_Get_Struct(obj,t_dbh,dbh);
906
+ if (!dbh->db)
907
+ raise(0, "db is closed");
908
+ rv=dbh->db->get_byteswapped(dbh->db,&is_swapped);
909
+ if (rv)
910
+ raise_error(rv,"db_get_byteswapped failed: %s",db_strerror(rv));
911
+ if (is_swapped)
912
+ return Qtrue;
913
+ else
914
+ return Qfalse;
915
+ }
916
+
917
+ /*
918
+ * call-seq:
919
+ * db.get_type -> Fixnum(type)
920
+ *
921
+ * an integer indicating the type of db (BTREE, HASH, etc).
922
+ */
923
+ VALUE db_get_type(VALUE obj)
924
+ {
925
+ t_dbh *dbh;
926
+ int rv;
927
+ DBTYPE dbtype;
928
+
929
+ Data_Get_Struct(obj,t_dbh,dbh);
930
+ if (!dbh->db)
931
+ raise(0, "db is closed");
932
+ rv=dbh->db->get_type(dbh->db,&dbtype);
933
+ if (rv)
934
+ raise_error(rv,"db_get_type failed: %s",db_strerror(rv));
935
+ return INT2FIX(dbtype);
936
+ }
937
+
938
+ /*
939
+ * call-seq:
940
+ * db.remove(disk_file,logical_db,flags) -> true
941
+ *
942
+ * removes a whole database file, or just a logical_db within
943
+ * that file, i.e. if file and logical are both specified, only
944
+ * the logical will be removed. the Bdb::Db instance cannot have
945
+ * been previously used for anything and cannot be used after.
946
+ */
947
+ VALUE db_remove(VALUE obj, VALUE vdisk_file,
948
+ VALUE vlogical_db, VALUE vflags)
949
+ {
950
+ t_dbh *dbh;
951
+ int rv;
952
+ u_int32_t flags=0;
953
+ //char *logical_db=NULL;
954
+
955
+ if ( ! NIL_P(vflags) )
956
+ flags=NUM2UINT(vflags);
957
+
958
+ Data_Get_Struct(obj,t_dbh,dbh);
959
+ if (!dbh->db)
960
+ raise(0, "db is closed");
961
+ rv=dbh->db->remove(dbh->db,
962
+ NIL_P(vdisk_file)?NULL:StringValueCStr(vdisk_file),
963
+ NIL_P(vlogical_db)?NULL:StringValueCStr(vlogical_db),
964
+ flags);
965
+ /* handle cannot be accessed again per docs */
966
+ dbh->db=NULL;
967
+ if (rv)
968
+ raise_error(rv,"db_remove failed: %s",db_strerror(rv));
969
+ return Qtrue;
970
+ }
971
+
972
+ /*
973
+ * call-seq:
974
+ * db.rename(file,logical,newname,flags) -> true
975
+ *
976
+ * rename a file or logical db to newname.
977
+ */
978
+ VALUE db_rename(VALUE obj, VALUE vdisk_file,
979
+ VALUE vlogical_db, VALUE newname, VALUE vflags)
980
+ {
981
+ t_dbh *dbh;
982
+ int rv;
983
+ u_int32_t flags=0;
984
+ //char *disk_file=NULL;
985
+ //char *logical_db=NULL;
986
+
987
+ if ( ! NIL_P(vflags) )
988
+ flags=NUM2UINT(vflags);
989
+
990
+ if ( NIL_P(newname) )
991
+ raise_error(0,"db_rename newname must be specified");
992
+
993
+ Data_Get_Struct(obj,t_dbh,dbh);
994
+ if (!dbh->db)
995
+ raise(0, "db is closed");
996
+ rv=dbh->db->rename(dbh->db,
997
+ NIL_P(vdisk_file)?NULL:StringValueCStr(vdisk_file),
998
+ NIL_P(vlogical_db)?NULL:StringValueCStr(vlogical_db),
999
+ StringValueCStr(newname),
1000
+ flags);
1001
+
1002
+ if (rv) {
1003
+ raise_error(rv,"db_rename failed: %s",db_strerror(rv));
1004
+ }
1005
+ return Qtrue;
1006
+ }
1007
+
1008
+ /*
1009
+ * call-seq:
1010
+ * db.sync -> true
1011
+ *
1012
+ * sync the database out to storage.
1013
+ */
1014
+ VALUE db_sync(VALUE obj)
1015
+ {
1016
+ t_dbh *dbh;
1017
+ int rv;
1018
+
1019
+ Data_Get_Struct(obj,t_dbh,dbh);
1020
+ if (!dbh->db)
1021
+ raise(0, "db is closed");
1022
+ rv=dbh->db->sync(dbh->db,NOFLAGS);
1023
+
1024
+ if (rv)
1025
+ raise_error(rv,"db_sync failed: %s",db_strerror(rv));
1026
+ return Qtrue;
1027
+ }
1028
+
1029
+ /*
1030
+ * call-seq:
1031
+ * db.truncate(txn) -> Fixnum(record_count)
1032
+ *
1033
+ * truncate, i.e. remove all records, purge, trash.
1034
+ *
1035
+ */
1036
+ VALUE db_truncate(VALUE obj, VALUE vtxn)
1037
+ {
1038
+ t_dbh *dbh;
1039
+ t_txnh *txn=NULL;
1040
+ int rv;
1041
+ //VALUE result;
1042
+ u_int32_t count;
1043
+
1044
+ if ( ! NIL_P(vtxn) ) {
1045
+ Data_Get_Struct(vtxn,t_txnh,txn);
1046
+ if (!txn->txn)
1047
+ raise(0, "txn is closed");
1048
+ }
1049
+
1050
+ Data_Get_Struct(obj,t_dbh,dbh);
1051
+ if (!dbh->db)
1052
+ raise(0, "db is closed");
1053
+
1054
+ rv=dbh->db->truncate(dbh->db,txn?txn->txn:NULL,&count,NOFLAGS);
1055
+ if (rv)
1056
+ raise_error(rv,"db_truncate: %s",db_strerror(rv));
1057
+
1058
+ return INT2FIX(count);
1059
+ }
1060
+
1061
+ /*
1062
+ * call-seq:
1063
+ * db.key_range(txn,vkey,flags) -> [#less,#same,#greater]
1064
+ *
1065
+ * calculate position of key within database. returns the counts
1066
+ * of keys less, same and greater than the given key as an
1067
+ * array of Fixnum-s
1068
+ */
1069
+ VALUE db_key_range(VALUE obj, VALUE vtxn, VALUE vkey, VALUE vflags)
1070
+ {
1071
+ t_dbh *dbh;
1072
+ t_txnh *txn=NULL;
1073
+ DBT key;
1074
+ u_int32_t flags = 0;
1075
+ int rv;
1076
+ DB_KEY_RANGE key_range;
1077
+ VALUE result;
1078
+
1079
+ if ( ! NIL_P(vtxn) ) {
1080
+ Data_Get_Struct(vtxn,t_txnh,txn);
1081
+ if (!txn->txn)
1082
+ raise(0, "txn is closed");
1083
+ }
1084
+
1085
+ if ( ! NIL_P(vflags) )
1086
+ flags=NUM2UINT(vflags);
1087
+
1088
+ Data_Get_Struct(obj,t_dbh,dbh);
1089
+ if (!dbh->db)
1090
+ raise(0, "db is closed");
1091
+
1092
+ memset(&key,0,sizeof(DBT));
1093
+ StringValue(vkey);
1094
+ key.data = RSTRING_PTR(vkey);
1095
+ key.size = RSTRING_LEN(vkey);
1096
+ key.flags = LMEMFLAG;
1097
+
1098
+ rv=dbh->db->key_range(dbh->db,txn?txn->txn:NULL,&key,
1099
+ &key_range,flags);
1100
+ if (rv)
1101
+ raise_error(rv,"db_key_range: %s",db_strerror(rv));
1102
+
1103
+ result=rb_ary_new3(3,
1104
+ rb_float_new(key_range.less),
1105
+ rb_float_new(key_range.equal),
1106
+ rb_float_new(key_range.greater));
1107
+ return result;
1108
+ }
1109
+
1110
+ /*
1111
+ * call-seq:
1112
+ * db.del(txn,key,flags) -> true/nil
1113
+ *
1114
+ * delete records with the key given. DUP values will removed
1115
+ * as a group. true if deleted extant records. NIL if the
1116
+ * operation resulted in DB indicating DB_NOTFOUND.
1117
+ *
1118
+ */
1119
+ VALUE db_del(VALUE obj, VALUE vtxn, VALUE vkey, VALUE vflags)
1120
+ {
1121
+ t_dbh *dbh;
1122
+ int rv;
1123
+ u_int32_t flags;
1124
+ DBT key;
1125
+ //VALUE str;
1126
+ t_txnh *txn=NULL;
1127
+
1128
+ memset(&key,0,sizeof(DBT));
1129
+
1130
+ if ( ! NIL_P(vtxn) ) {
1131
+ Data_Get_Struct(vtxn,t_txnh,txn);
1132
+ if (!txn->txn)
1133
+ raise(0, "txn is closed");
1134
+ }
1135
+
1136
+ flags=NUM2UINT(vflags);
1137
+ Data_Get_Struct(obj,t_dbh,dbh);
1138
+ if (!dbh->db)
1139
+ raise(0, "db is closed");
1140
+
1141
+ StringValue(vkey);
1142
+ key.data = RSTRING_PTR(vkey);
1143
+ key.size = RSTRING_LEN(vkey);
1144
+ key.flags = LMEMFLAG;
1145
+
1146
+ rv = dbh->db->del(dbh->db,txn?txn->txn:NULL,&key,flags);
1147
+ if ( rv == DB_NOTFOUND ) {
1148
+ return Qnil;
1149
+ } else if (rv != 0) {
1150
+ raise_error(rv, "db_del failure: %s",db_strerror(rv));
1151
+ }
1152
+ return Qtrue;
1153
+ }
1154
+
1155
+ void assoc_key(DBT* result, VALUE obj) {
1156
+ VALUE key = StringValue(obj);
1157
+ int len = RSTRING_LEN(key);
1158
+ char *str = malloc(len);
1159
+ memcpy(str, RSTRING_PTR(key), len);
1160
+
1161
+ #ifdef DEBUG_DB
1162
+ fprintf(stderr,"assoc_key %*s", len, str);
1163
+ #endif
1164
+
1165
+ result->size = len;
1166
+ result->flags = LMEMFLAG | DB_DBT_APPMALLOC;
1167
+ result->data = str;
1168
+ }
1169
+
1170
+ VALUE assoc_call(VALUE *args)
1171
+ {
1172
+ return rb_funcall(args[0],fv_call,3,args[1],args[2],args[3]);
1173
+ }
1174
+
1175
+ VALUE assoc_rescue(VALUE *error, VALUE e)
1176
+ {
1177
+ VALUE message = StringValue(e);
1178
+ rb_warn(RSTRING_PTR(message));
1179
+ *error = e;
1180
+ return Qnil;
1181
+ }
1182
+
1183
+ int assoc_callback(DB *secdb, const DBT* pkey, const DBT* data, DBT* skey)
1184
+ {
1185
+ t_dbh *dbh;
1186
+ //VALUE proc;
1187
+ VALUE error = Qnil;
1188
+ VALUE retv;
1189
+ VALUE args[4];
1190
+ VALUE keys;
1191
+ int i;
1192
+
1193
+ memset(skey,0,sizeof(DBT));
1194
+ dbh=secdb->app_private;
1195
+
1196
+ args[0]=dbh->aproc;
1197
+ args[1]=dbh->self;
1198
+ args[2]=rb_str_new(pkey->data,pkey->size);
1199
+ args[3]=rb_str_new(data->data,data->size);
1200
+
1201
+ #ifdef DEBUG_DB
1202
+ fprintf(stderr,"assoc_data %*s", data->size, data->data);
1203
+ #endif
1204
+
1205
+ retv=rb_rescue((VALUE(*)_((VALUE)))assoc_call,(VALUE)args,(VALUE(*)_((VALUE)))assoc_rescue,(VALUE)&error);
1206
+
1207
+ if (!NIL_P(error)) return 99999;
1208
+ if (NIL_P(retv))
1209
+ return DB_DONOTINDEX;
1210
+
1211
+ keys = rb_check_array_type(retv);
1212
+ if (!NIL_P(keys)) {
1213
+ keys = rb_funcall(keys,fv_uniq,0); /* secondary keys must be uniq */
1214
+ switch(RARRAY_LEN(keys)) {
1215
+ case 0:
1216
+ return DB_DONOTINDEX;
1217
+ case 1:
1218
+ retv=RARRAY_PTR(keys)[0];
1219
+ break;
1220
+ default:
1221
+ skey->size = RARRAY_LEN(keys);
1222
+ skey->flags = LMEMFLAG | DB_DBT_MULTIPLE | DB_DBT_APPMALLOC;
1223
+ skey->data = malloc(skey->size * sizeof(DBT));
1224
+ memset(skey->data, 0, skey->size * sizeof(DBT));
1225
+
1226
+ for (i=0; i<skey->size; i++) {
1227
+ assoc_key(skey->data + i * sizeof(DBT), (VALUE)RARRAY_PTR(keys)[i]);
1228
+ }
1229
+ return 0;
1230
+ }
1231
+ }
1232
+
1233
+ assoc_key(skey, retv);
1234
+ return 0;
1235
+ }
1236
+
1237
+ /*
1238
+ * call-seq:
1239
+ * db.associate(txn,sec_db,flags,proc)
1240
+ *
1241
+ * associate a secondary index(database) with this (primary)
1242
+ * database. The proc can be nil if the database is only opened
1243
+ * DB_RDONLY.
1244
+ *
1245
+ * call back proc has signature:
1246
+ * proc(secdb,key,value)
1247
+ */
1248
+ VALUE db_associate(VALUE obj, VALUE vtxn, VALUE osecdb,
1249
+ VALUE vflags, VALUE cb_proc)
1250
+ {
1251
+ t_dbh *sdbh,*pdbh;
1252
+ int rv;
1253
+ u_int32_t flags,flagsp,flagss;
1254
+ //int fdp;
1255
+ t_txnh *txn=NOTXN;
1256
+
1257
+ flags=NUM2UINT(vflags);
1258
+ Data_Get_Struct(obj,t_dbh,pdbh);
1259
+ if (!pdbh->db)
1260
+ raise(0, "db is closed");
1261
+ Data_Get_Struct(osecdb,t_dbh,sdbh);
1262
+ if (!sdbh->db)
1263
+ raise(0, "sdb is closed");
1264
+
1265
+ if ( ! NIL_P(vtxn) ) {
1266
+ Data_Get_Struct(vtxn,t_txnh,txn);
1267
+ if (!txn->txn)
1268
+ raise(0, "txn is closed");
1269
+ }
1270
+
1271
+ if ( cb_proc == Qnil ) {
1272
+ rb_warning("db_associate: no association may be applied");
1273
+ pdbh->db->get_open_flags(pdbh->db,&flagsp);
1274
+ sdbh->db->get_open_flags(sdbh->db,&flagss);
1275
+ if ( flagsp & DB_RDONLY & flagss ) {
1276
+ rv=pdbh->db->associate(pdbh->db,txn?txn->txn:NULL,
1277
+ sdbh->db,NULL,flags);
1278
+ if (rv)
1279
+ raise_error(rv,"db_associate: %s",db_strerror(rv));
1280
+ return Qtrue;
1281
+ } else {
1282
+ raise_error(0,"db_associate empty associate only available when both DBs opened with DB_RDONLY");
1283
+ }
1284
+ } else if ( rb_obj_is_instance_of(cb_proc,rb_cProc) != Qtrue ) {
1285
+ raise_error(0, "db_associate proc required");
1286
+ }
1287
+
1288
+ sdbh->aproc=cb_proc;
1289
+
1290
+ rv=pdbh->db->associate(pdbh->db,txn?txn->txn:NULL,sdbh->db,assoc_callback,flags);
1291
+ #ifdef DEBUG_DB
1292
+ fprintf(stderr,"file is %d\n",fdp);
1293
+ fprintf(stderr,"assoc done 0x%x\n",sdbh);
1294
+ #endif
1295
+ if (rv != 0) {
1296
+ raise_error(rv, "db_associate failure: %s",db_strerror(rv));
1297
+ }
1298
+ return Qtrue;
1299
+ }
1300
+
1301
+ VALUE
1302
+ bt_compare_callback2(VALUE *args)
1303
+ {
1304
+ return rb_funcall(args[0],fv_call,3,args[1],args[2],args[3]);
1305
+ }
1306
+
1307
+ int bt_compare_callback(DB *db, const DBT* key1, const DBT* key2)
1308
+ {
1309
+ t_dbh *dbh;
1310
+ //VALUE proc;
1311
+ int cmp;
1312
+ VALUE retv;
1313
+
1314
+ dbh=db->app_private;
1315
+
1316
+ /* Shouldn't catch exceptions in the callback, because bad sort data will corrupt the BTree.*/
1317
+ retv=rb_funcall(dbh->sproc,fv_call,3,dbh->self,
1318
+ rb_str_new(key1->data,key1->size),rb_str_new(key2->data,key2->size));
1319
+
1320
+ if (!FIXNUM_P(retv))
1321
+ rb_raise(rb_eTypeError,"btree comparison should return Fixnum");
1322
+
1323
+ cmp=FIX2INT(retv);
1324
+
1325
+ #ifdef DEBUG_DB
1326
+ fprintf(stderr,"bt_compare %*s <=> %*s: %d", key1->size, key1->data, key2->size, key2->data, cmp);
1327
+ #endif
1328
+
1329
+ return cmp;
1330
+ }
1331
+
1332
+ /*
1333
+ * call-seq:
1334
+ * db.btree_compare = proc
1335
+ *
1336
+ * set the btree key comparison function to the callback proc.
1337
+ *
1338
+ * callback proc has signature:
1339
+ * proc(db,key1,key2)
1340
+ */
1341
+ VALUE db_btree_compare_set(VALUE obj, VALUE cb_proc)
1342
+ {
1343
+ t_dbh *dbh;
1344
+ int rv;
1345
+
1346
+ Data_Get_Struct(obj,t_dbh,dbh);
1347
+ if (!dbh->db)
1348
+ raise(0, "db is closed");
1349
+
1350
+ if ( rb_obj_is_instance_of(cb_proc,rb_cProc) != Qtrue ) {
1351
+ raise_error(0, "db_associate proc required");
1352
+ }
1353
+
1354
+ dbh->sproc=cb_proc;
1355
+ rv=dbh->db->set_bt_compare(dbh->db,bt_compare_callback);
1356
+
1357
+ #ifdef DEBUG_DB
1358
+ fprintf(stderr,"btree_compare set 0x%x\n",dbh);
1359
+ #endif
1360
+ if (rv != 0) {
1361
+ raise_error(rv, "db_btree_compare_set failure: %s",db_strerror(rv));
1362
+ }
1363
+ return Qtrue;
1364
+ }
1365
+
1366
+ /*
1367
+ * call-seq:
1368
+ * db.cursor(txn,flags)
1369
+ *
1370
+ * open a cursor
1371
+ */
1372
+ VALUE db_cursor(VALUE obj, VALUE vtxn, VALUE vflags)
1373
+ {
1374
+ t_dbh *dbh;
1375
+ int rv;
1376
+ u_int32_t flags;
1377
+ //DBC *dbc;
1378
+ t_txnh *txn=NOTXN;
1379
+ VALUE c_obj;
1380
+ t_dbch *dbch;
1381
+
1382
+ flags=NUM2UINT(vflags);
1383
+ Data_Get_Struct(obj,t_dbh,dbh);
1384
+ if (!dbh->db)
1385
+ raise(0, "db is closed");
1386
+
1387
+ c_obj=Data_Make_Struct(cCursor, t_dbch, dbc_mark, dbc_free, dbch);
1388
+
1389
+ if ( ! NIL_P(vtxn) ) {
1390
+ Data_Get_Struct(vtxn,t_txnh,txn);
1391
+ if (!txn->txn)
1392
+ raise(0, "txn is closed");
1393
+ }
1394
+
1395
+ rv=dbh->db->cursor(dbh->db,txn?txn->txn:NULL,&(dbch->dbc),flags);
1396
+ if (rv)
1397
+ raise_error(rv,"db_cursor: %s",db_strerror(rv));
1398
+
1399
+ filename_dup(dbch->filename,dbh->filename);
1400
+ dbch->db=dbh;
1401
+ rb_ary_push(dbch->db->adbc,c_obj);
1402
+ rb_obj_call_init(c_obj,0,NULL);
1403
+ return c_obj;
1404
+ }
1405
+
1406
+ /*
1407
+ * call-seq:
1408
+ * dbc.close -> nil
1409
+ *
1410
+ * close an open cursor
1411
+ */
1412
+ VALUE dbc_close(VALUE obj)
1413
+ {
1414
+ t_dbch *dbch;
1415
+ int rv;
1416
+ Data_Get_Struct(obj,t_dbch,dbch);
1417
+ if ( dbch->dbc ) {
1418
+ rv=dbch->dbc->c_close(dbch->dbc);
1419
+ rb_ary_delete(dbch->db->adbc,obj);
1420
+ dbch->db=NULL;
1421
+ dbch->dbc=NULL;
1422
+ if (rv)
1423
+ raise_error(rv,"dbc_close: %s",db_strerror(rv));
1424
+ }
1425
+ return Qnil;
1426
+ }
1427
+
1428
+ /*
1429
+ * call-seq:
1430
+ * dbc.get(key,data,flags) -> [key,data]
1431
+ *
1432
+ * get data by key or key and data. returns array of key,data
1433
+ */
1434
+ VALUE dbc_get(VALUE obj, VALUE vkey, VALUE vdata, VALUE vflags)
1435
+ {
1436
+ t_dbch *dbch;
1437
+ u_int32_t flags;
1438
+ DBT key,data;
1439
+ VALUE rar;
1440
+ int rv;
1441
+
1442
+ flags=NUM2UINT(vflags);
1443
+ Data_Get_Struct(obj,t_dbch,dbch);
1444
+ if (!dbch->dbc)
1445
+ raise(0, "dbc is closed");
1446
+
1447
+ memset(&key,0,sizeof(DBT));
1448
+ memset(&data,0,sizeof(DBT));
1449
+
1450
+ if ( ! NIL_P(vkey) ) {
1451
+ StringValue(vkey);
1452
+ key.data = RSTRING_PTR(vkey);
1453
+ key.size = RSTRING_LEN(vkey);
1454
+ key.flags = LMEMFLAG;
1455
+ }
1456
+ if ( ! NIL_P(vdata) ) {
1457
+ StringValue(vdata);
1458
+ data.data = RSTRING_PTR(vdata);
1459
+ data.size = RSTRING_LEN(vdata);
1460
+ data.flags = LMEMFLAG;
1461
+ }
1462
+
1463
+ rv = dbch->dbc->c_get(dbch->dbc,&key,&data,flags);
1464
+ if ( rv == 0 ) {
1465
+ rar = rb_ary_new3(2,rb_str_new(key.data,key.size),
1466
+ rb_str_new(data.data,data.size));
1467
+ return rar;
1468
+ } else if (rv == DB_NOTFOUND) {
1469
+ return Qnil;
1470
+ } else {
1471
+ raise_error(rv, "dbc_get %s",db_strerror(rv));
1472
+ }
1473
+ return Qnil;
1474
+ }
1475
+ /*
1476
+ * call-seq:
1477
+ * dbc.pget(key,data,flags) -> [key,pkey,data]
1478
+ *
1479
+ * cursor pget, returns array(key, primary key, data)
1480
+ */
1481
+ VALUE dbc_pget(VALUE obj, VALUE vkey, VALUE vdata, VALUE vflags)
1482
+ {
1483
+ t_dbch *dbch;
1484
+ u_int32_t flags;
1485
+ DBT key,data,pkey;
1486
+ VALUE rar;
1487
+ int rv;
1488
+
1489
+ flags=NUM2UINT(vflags);
1490
+ Data_Get_Struct(obj,t_dbch,dbch);
1491
+ if (!dbch->dbc)
1492
+ raise(0, "dbc is closed");
1493
+
1494
+ memset(&key,0,sizeof(DBT));
1495
+ memset(&data,0,sizeof(DBT));
1496
+ memset(&pkey,0,sizeof(DBT));
1497
+
1498
+ if ( ! NIL_P(vkey) ) {
1499
+ StringValue(vkey);
1500
+ key.data = RSTRING_PTR(vkey);
1501
+ key.size = RSTRING_LEN(vkey);
1502
+ key.flags = LMEMFLAG;
1503
+ }
1504
+ if ( ! NIL_P(vdata) ) {
1505
+ StringValue(vdata);
1506
+ data.data = RSTRING_PTR(vdata);
1507
+ data.size = RSTRING_LEN(vdata);
1508
+ data.flags = LMEMFLAG;
1509
+ }
1510
+
1511
+ rv = dbch->dbc->c_pget(dbch->dbc,&key,&pkey,&data,flags);
1512
+ if ( rv == 0 ) {
1513
+ rar = rb_ary_new3(3,
1514
+ rb_str_new(key.data,key.size),
1515
+ rb_str_new(pkey.data,pkey.size),
1516
+ rb_str_new(data.data,data.size));
1517
+ return rar;
1518
+ } else if (rv == DB_NOTFOUND) {
1519
+ return Qnil;
1520
+ } else {
1521
+ raise_error(rv, "dbc_pget %s",db_strerror(rv));
1522
+ }
1523
+ return Qnil;
1524
+ }
1525
+
1526
+ /*
1527
+ * call-seq:
1528
+ * dbc.put(key,data,flags) -> data
1529
+ *
1530
+ * cursor put key/data
1531
+ */
1532
+ VALUE dbc_put(VALUE obj, VALUE vkey, VALUE vdata, VALUE vflags)
1533
+ {
1534
+ t_dbch *dbch;
1535
+ u_int32_t flags;
1536
+ DBT key,data;
1537
+ int rv;
1538
+
1539
+ if ( NIL_P(vdata) )
1540
+ raise_error(0,"data element is required for put");
1541
+
1542
+ flags=NUM2UINT(vflags);
1543
+ Data_Get_Struct(obj,t_dbch,dbch);
1544
+ if (!dbch->dbc)
1545
+ raise(0, "dbc is closed");
1546
+
1547
+ memset(&key,0,sizeof(DBT));
1548
+ memset(&data,0,sizeof(DBT));
1549
+
1550
+ if ( ! NIL_P(vkey) ) {
1551
+ StringValue(vkey);
1552
+ key.data = RSTRING_PTR(vkey);
1553
+ key.size = RSTRING_LEN(vkey);
1554
+ key.flags = LMEMFLAG;
1555
+ }
1556
+
1557
+ StringValue(vdata);
1558
+ data.data = RSTRING_PTR(vdata);
1559
+ data.size = RSTRING_LEN(vdata);
1560
+ data.flags = LMEMFLAG;
1561
+
1562
+ rv = dbch->dbc->c_put(dbch->dbc,&key,&data,flags);
1563
+ if (rv != 0)
1564
+ raise_error(rv,"dbc_put failure: %s",db_strerror(rv));
1565
+
1566
+ return vdata;
1567
+ }
1568
+
1569
+ /*
1570
+ * call-seq:
1571
+ * dbc.del -> true|nil
1572
+ *
1573
+ * delete tuple at current cursor position. returns true if
1574
+ * something was deleted, nil otherwise (DB_KEYEMPTY)
1575
+ *
1576
+ */
1577
+ VALUE dbc_del(VALUE obj)
1578
+ {
1579
+ t_dbch *dbch;
1580
+ int rv;
1581
+
1582
+ Data_Get_Struct(obj,t_dbch,dbch);
1583
+ if (!dbch->dbc)
1584
+ raise(0, "dbc is closed");
1585
+ rv = dbch->dbc->c_del(dbch->dbc,NOFLAGS);
1586
+ if (rv == DB_KEYEMPTY)
1587
+ return Qnil;
1588
+ else if (rv != 0) {
1589
+ raise_error(rv, "dbc_del failure: %s",db_strerror(rv));
1590
+ }
1591
+ return Qtrue;
1592
+ }
1593
+
1594
+ /*
1595
+ * call-seq:
1596
+ * dbc.count -> Fixnum(count)
1597
+ *
1598
+ * returns cursor count as per DB.
1599
+ */
1600
+ VALUE dbc_count(VALUE obj)
1601
+ {
1602
+ t_dbch *dbch;
1603
+ int rv;
1604
+ db_recno_t count;
1605
+
1606
+ Data_Get_Struct(obj,t_dbch,dbch);
1607
+ if (!dbch->dbc)
1608
+ raise(0, "dbc is closed");
1609
+ rv = dbch->dbc->c_count(dbch->dbc,&count,NOFLAGS);
1610
+ if (rv != 0)
1611
+ raise_error(rv, "db_count failure: %s",db_strerror(rv));
1612
+
1613
+ return INT2FIX(count);
1614
+ }
1615
+
1616
+ static void env_free(void *p)
1617
+ {
1618
+ t_envh *eh;
1619
+ eh=(t_envh *)p;
1620
+
1621
+ #ifdef DEBUG_DB
1622
+ if ( RTEST(ruby_debug) )
1623
+ fprintf(stderr,"%s/%d %s 0x%x\n",__FILE__,__LINE__,"env_free cleanup!",p);
1624
+ #endif
1625
+
1626
+ if ( eh ) {
1627
+ if ( eh->env ) {
1628
+ eh->env->close(eh->env,NOFLAGS);
1629
+ eh->env=NULL;
1630
+ }
1631
+ free(p);
1632
+ }
1633
+ }
1634
+ static void env_mark(t_envh *eh)
1635
+ {
1636
+ rb_gc_mark(eh->adb);
1637
+ rb_gc_mark(eh->atxn);
1638
+ }
1639
+
1640
+ /*
1641
+ * Document-class: Bdb::Env
1642
+ *
1643
+ * Encapsulated DB environment. Create by simple new (with
1644
+ * flags as neede), then open. Database handles created with
1645
+ * env.db -> Bdb::Db object.
1646
+ */
1647
+
1648
+ /*
1649
+ * call-seq:
1650
+ * new(flags) -> object
1651
+ *
1652
+ *
1653
+ */
1654
+ VALUE env_new(VALUE class, VALUE vflags)
1655
+ {
1656
+ t_envh *eh;
1657
+ int rv;
1658
+ u_int32_t flags=0;
1659
+ VALUE obj;
1660
+
1661
+ if ( ! NIL_P(vflags) )
1662
+ flags=NUM2UINT(vflags);
1663
+
1664
+ obj=Data_Make_Struct(class,t_envh,env_mark,env_free,eh);
1665
+ rv=db_env_create(&(eh->env),flags);
1666
+ if ( rv != 0 ) {
1667
+ raise_error(rv,"env_new: %s",db_strerror(rv));
1668
+ return Qnil;
1669
+ }
1670
+ eh->self=obj;
1671
+ eh->adb = rb_ary_new();
1672
+ eh->atxn = rb_ary_new();
1673
+ rb_obj_call_init(obj,0,NULL);
1674
+ return obj;
1675
+ }
1676
+
1677
+ /*
1678
+ * call-seq:
1679
+ * env.open(homedir,flags,mode) -> self
1680
+ *
1681
+ * open an environment
1682
+ */
1683
+ VALUE env_open(VALUE obj, VALUE vhome, VALUE vflags, VALUE vmode)
1684
+ {
1685
+ t_envh *eh;
1686
+ int rv;
1687
+ u_int32_t flags=0;
1688
+ int mode=0;
1689
+
1690
+ if ( ! NIL_P(vflags) )
1691
+ flags=NUM2UINT(vflags);
1692
+ if ( ! NIL_P(vmode) )
1693
+ mode=NUM2INT(vmode);
1694
+ Data_Get_Struct(obj,t_envh,eh);
1695
+ if (!eh->env)
1696
+ raise(0, "env is closed");
1697
+ if ( NIL_P(eh->adb) )
1698
+ raise_error(0,"env handle already used and closed");
1699
+
1700
+ rv = eh->env->open(eh->env,StringValueCStr(vhome),flags,mode);
1701
+ eh->env->app_private=eh;
1702
+
1703
+ if (rv != 0) {
1704
+ raise_error(rv, "env_open failure: %s",db_strerror(rv));
1705
+ }
1706
+ return obj;
1707
+ }
1708
+
1709
+ VALUE txn_abort(VALUE);
1710
+
1711
+ /*
1712
+ * call-seq:
1713
+ * env.close -> self
1714
+ *
1715
+ * close an environment. Do not use it after you close it.
1716
+ * The close process will automatically abort any open transactions
1717
+ * and close open databases (which also closes open cursors).
1718
+ * But this is just an effort to keep your dbs and envs from
1719
+ * becoming corrupted due to ruby errors that exit
1720
+ * unintentionally. However, to make this at all worth anything
1721
+ * use ObjectSpace.define_finalizer which calls env.close to
1722
+ * approach some assurance of it happening.
1723
+ *
1724
+ */
1725
+ VALUE env_close(VALUE obj)
1726
+ {
1727
+ t_envh *eh;
1728
+ VALUE db;
1729
+ int rv;
1730
+
1731
+ Data_Get_Struct(obj,t_envh,eh);
1732
+ if ( eh->env==NULL )
1733
+ return Qnil;
1734
+
1735
+ if (RARRAY_LEN(eh->adb) > 0) {
1736
+ rb_warning("%s/%d %s %li",__FILE__,__LINE__,
1737
+ "database handles still open",RARRAY_LEN(eh->adb));
1738
+ while (RARRAY_LEN(eh->adb) > 0)
1739
+ if ((db=rb_ary_pop(eh->adb)) != Qnil ) {
1740
+ rb_warning("%s/%d %s 0x%p",__FILE__,__LINE__,
1741
+ "closing",(void*)db);
1742
+ /* this could raise! needs rb_protect */
1743
+ db_close(db,INT2FIX(0));
1744
+ }
1745
+ }
1746
+ if (RARRAY_LEN(eh->atxn) > 0) {
1747
+ rb_warning("%s/%d %s",__FILE__,__LINE__,
1748
+ "database transactions still open");
1749
+ while ( (db=rb_ary_pop(eh->atxn)) != Qnil ) {
1750
+ /* this could raise! needs rb_protect */
1751
+ txn_abort(db);
1752
+ }
1753
+ }
1754
+
1755
+ if ( RTEST(ruby_debug) )
1756
+ rb_warning("%s/%d %s 0x%p",__FILE__,__LINE__,"env_close!",(void*)eh);
1757
+
1758
+ rv = eh->env->close(eh->env,NOFLAGS);
1759
+ eh->env=NULL;
1760
+ eh->adb=Qnil;
1761
+ eh->atxn=Qnil;
1762
+ if ( rv != 0 ) {
1763
+ raise_error(rv, "env_close failure: %s",db_strerror(rv));
1764
+ return Qnil;
1765
+ }
1766
+ return obj;
1767
+ }
1768
+
1769
+ /*
1770
+ * call-seq:
1771
+ * env.db -> Bdb::Db instance
1772
+ *
1773
+ * create a db associated with an environment
1774
+ */
1775
+ VALUE env_db(VALUE obj)
1776
+ {
1777
+ t_envh *eh;
1778
+ VALUE dbo;
1779
+
1780
+ Data_Get_Struct(obj,t_envh,eh);
1781
+ if (!eh->env)
1782
+ raise(0, "env is closed");
1783
+ dbo = Data_Wrap_Struct(cDb,db_mark,db_free,0);
1784
+
1785
+ return db_init_aux(dbo,eh);
1786
+ }
1787
+
1788
+ /*
1789
+ * call-seq:
1790
+ * env.cachesize=Fixnum|Bignum
1791
+ *
1792
+ * set the environment cache size. If it is a Bignum then it
1793
+ * will populate the bytes and gbytes part of the DB struct.
1794
+ * Fixnums will only populate bytes (which is still pretty big).
1795
+ */
1796
+ VALUE env_set_cachesize(VALUE obj, VALUE size)
1797
+ {
1798
+ t_envh *eh;
1799
+ unsigned long long ln;
1800
+ u_int32_t bytes=0,gbytes=0;
1801
+ int rv;
1802
+ Data_Get_Struct(obj,t_envh,eh);
1803
+ if (!eh->env)
1804
+ raise(0, "env is closed");
1805
+
1806
+ if ( TYPE(size) == T_BIGNUM ) {
1807
+ ln = rb_big2ull(size);
1808
+ gbytes = ln / (1024*1024*1024);
1809
+ bytes = ln - (gbytes*1024*1024*1024);
1810
+ } else if (FIXNUM_P(size) ) {
1811
+ bytes=NUM2UINT(size);
1812
+ } else {
1813
+ raise_error(0,"set_cachesize requires number");
1814
+ return Qnil;
1815
+ }
1816
+
1817
+ rv=eh->env->set_cachesize(eh->env,gbytes,bytes,1);
1818
+ if ( rv != 0 ) {
1819
+ raise_error(rv, "set_cachesize failure: %s",db_strerror(rv));
1820
+ return Qnil;
1821
+ }
1822
+
1823
+ return Qtrue;
1824
+ }
1825
+
1826
+ /*
1827
+ * call-seq:
1828
+ * env.cachesize -> Fixnum|Bignum
1829
+ *
1830
+ * return the environment cache size. If it is a Bignum then it
1831
+ * will populate the bytes and gbytes part of the DB struct.
1832
+ * Fixnums will only populate bytes (which is still pretty big).
1833
+ */
1834
+ VALUE env_get_cachesize(VALUE obj)
1835
+ {
1836
+ t_envh *eh;
1837
+ //unsigned long long ln;
1838
+ u_int32_t bytes=0,gbytes=0;
1839
+ int ncache;
1840
+ int rv;
1841
+ Data_Get_Struct(obj,t_envh,eh);
1842
+ if (!eh->env)
1843
+ raise(0, "env is closed");
1844
+
1845
+ rv=eh->env->get_cachesize(eh->env,&gbytes,&bytes,&ncache);
1846
+ if ( rv != 0 ) {
1847
+ raise_error(rv, "get_cachesize failure: %s",db_strerror(rv));
1848
+ return Qnil;
1849
+ }
1850
+
1851
+ if (gbytes != 0)
1852
+ return ULL2NUM(gbytes*1024*1024*1024+bytes);
1853
+ else
1854
+ return UINT2NUM(bytes);
1855
+
1856
+ return Qtrue;
1857
+ }
1858
+
1859
+ VALUE env_set_flags(VALUE obj, VALUE vflags, int onoff)
1860
+ {
1861
+ t_envh *eh;
1862
+ int rv;
1863
+ u_int32_t flags;
1864
+
1865
+ Data_Get_Struct(obj,t_envh,eh);
1866
+ if (!eh->env)
1867
+ raise(0, "env is closed");
1868
+ if ( ! NIL_P(vflags) ) {
1869
+ flags=NUM2UINT(vflags);
1870
+
1871
+ rv=eh->env->set_flags(eh->env,flags,onoff);
1872
+
1873
+ if ( rv != 0 ) {
1874
+ raise_error(rv, "set_flags failure: %s",db_strerror(rv));
1875
+ return Qnil;
1876
+ }
1877
+ }
1878
+ return Qtrue;
1879
+ }
1880
+
1881
+ /*
1882
+ * call-seq:
1883
+ * env.flags -> flags
1884
+ *
1885
+ * get what flags are on.
1886
+ */
1887
+ VALUE env_get_flags(VALUE obj)
1888
+ {
1889
+ t_envh *eh;
1890
+ int rv;
1891
+ u_int32_t flags;
1892
+
1893
+ Data_Get_Struct(obj,t_envh,eh);
1894
+ if (!eh->env)
1895
+ raise(0, "env is closed");
1896
+
1897
+ rv=eh->env->get_flags(eh->env,&flags);
1898
+
1899
+ if ( rv != 0 ) {
1900
+ raise_error(rv, "set_flags failure: %s",db_strerror(rv));
1901
+ return Qnil;
1902
+ }
1903
+
1904
+ return UINT2NUM(flags);
1905
+ }
1906
+
1907
+ /*
1908
+ * call-seq:
1909
+ * env.flags_on=flags
1910
+ *
1911
+ * set the 'flags' on. An or'ed set of flags will be set on.
1912
+ * Only included flags will be affected. Serialized calls
1913
+ * will only affect flags indicated (leaving others, default or
1914
+ * set as they were).
1915
+ */
1916
+ VALUE env_set_flags_on(VALUE obj, VALUE vflags)
1917
+ {
1918
+ return env_set_flags(obj,vflags,1);
1919
+ }
1920
+
1921
+ /*
1922
+ * call-seq:
1923
+ * env.flags_off=flags
1924
+ *
1925
+ * set the 'flags' off. An or'ed set of flags will be set off.
1926
+ * Only included flags will be affected. Serialized calls
1927
+ * will only affect flags indicated (leaving others, default or
1928
+ * set as they were).
1929
+ */
1930
+ VALUE env_set_flags_off(VALUE obj, VALUE vflags)
1931
+ {
1932
+ return env_set_flags(obj,vflags,0);
1933
+ }
1934
+
1935
+ /*
1936
+ * call-seq:
1937
+ * env.list_dbs -> [Bdb::Db array]
1938
+ *
1939
+ * return 0 or more open databases within the receiver environment.
1940
+ * If 0, will return [], not nil.
1941
+ */
1942
+ VALUE env_list_dbs(VALUE obj)
1943
+ {
1944
+ t_envh *eh;
1945
+ Data_Get_Struct(obj,t_envh,eh);
1946
+ if (!eh->env)
1947
+ raise(0, "env is closed");
1948
+ return eh->adb;
1949
+ }
1950
+ static void txn_mark(t_txnh *txn)
1951
+ {
1952
+ if (txn->env)
1953
+ rb_gc_mark(txn->env->self);
1954
+ }
1955
+ static void txn_free(t_txnh *txn)
1956
+ {
1957
+ #ifdef DEBUG_DB
1958
+ if ( RTEST(ruby_debug) )
1959
+ fprintf(stderr,"%s/%d %s %p\n",__FILE__,__LINE__,"txn_free",txn);
1960
+ #endif
1961
+
1962
+ if (txn) {
1963
+ if (txn->txn)
1964
+ txn->txn->abort(txn->txn);
1965
+ txn->txn=NULL;
1966
+ if (txn->env) {
1967
+ rb_ary_delete(txn->env->atxn,txn->self);
1968
+ }
1969
+ txn->env=NULL;
1970
+
1971
+ free(txn);
1972
+ }
1973
+ }
1974
+
1975
+ /*
1976
+ * call-seq:
1977
+ * env.txn_begin(txn_parent,flags) -> Bdb::Txn
1978
+ *
1979
+ * start a root transaction or embedded (via txn_parent).
1980
+ */
1981
+ VALUE env_txn_begin(VALUE obj, VALUE vtxn_parent, VALUE vflags)
1982
+ {
1983
+ t_txnh *parent=NULL, *txn=NULL;
1984
+ u_int32_t flags=0;
1985
+ int rv;
1986
+ t_envh *eh;
1987
+ VALUE t_obj;
1988
+
1989
+ if ( ! NIL_P(vflags))
1990
+ flags=NUM2UINT(vflags);
1991
+ if ( ! NIL_P(vtxn_parent) ) {
1992
+ Data_Get_Struct(vtxn_parent,t_txnh,parent);
1993
+ if (!parent->txn)
1994
+ raise(0, "parent txn is closed");
1995
+ }
1996
+
1997
+ Data_Get_Struct(obj,t_envh,eh);
1998
+ if (!eh->env)
1999
+ raise(0, "env is closed");
2000
+ t_obj=Data_Make_Struct(cTxn,t_txnh,txn_mark,txn_free,txn);
2001
+
2002
+ rv=eh->env->txn_begin(eh->env,parent?parent->txn:NULL,
2003
+ &(txn->txn),flags);
2004
+
2005
+ if ( rv != 0 ) {
2006
+ raise_error(rv, "env_txn_begin: %s",db_strerror(rv));
2007
+ return Qnil;
2008
+ }
2009
+ txn->env=eh;
2010
+ txn->self=t_obj;
2011
+ rb_ary_push(eh->atxn,t_obj);
2012
+
2013
+ /* Once we get this working, we'll have to track transactions */
2014
+ rb_obj_call_init(t_obj,0,NULL);
2015
+ return t_obj;
2016
+ }
2017
+
2018
+ /*
2019
+ * call-seq:
2020
+ * env.txn_checkpoint -> true
2021
+ *
2022
+ * Cause env transaction state to be checkpointed.
2023
+ */
2024
+ VALUE env_txn_checkpoint(VALUE obj, VALUE vkbyte, VALUE vmin,
2025
+ VALUE vflags)
2026
+ {
2027
+ u_int32_t flags=0;
2028
+ int rv;
2029
+ t_envh *eh;
2030
+ u_int32_t kbyte=0, min=0;
2031
+
2032
+ if ( ! NIL_P(vflags))
2033
+ flags=NUM2UINT(vflags);
2034
+
2035
+ if ( FIXNUM_P(vkbyte) )
2036
+ kbyte=FIX2UINT(vkbyte);
2037
+
2038
+ if ( FIXNUM_P(vmin) )
2039
+ min=FIX2UINT(vmin);
2040
+
2041
+ Data_Get_Struct(obj,t_envh,eh);
2042
+ if (!eh->env)
2043
+ raise(0, "env is closed");
2044
+ rv=eh->env->txn_checkpoint(eh->env,kbyte,min,flags);
2045
+ if ( rv != 0 ) {
2046
+ raise_error(rv, "env_txn_checkpoint: %s",db_strerror(rv));
2047
+ return Qnil;
2048
+ }
2049
+ return Qtrue;
2050
+ }
2051
+
2052
+ VALUE env_txn_stat_active(DB_TXN_ACTIVE *t)
2053
+ {
2054
+ VALUE ao;
2055
+
2056
+ ao=rb_class_new_instance(0,NULL,cTxnStatActive);
2057
+
2058
+ rb_iv_set(ao,"@txnid",INT2FIX(t->txnid));
2059
+ rb_iv_set(ao,"@parentid",INT2FIX(t->parentid));
2060
+ /* rb_iv_set(ao,"@thread_id",INT2FIX(t->thread_id)); */
2061
+ rb_iv_set(ao,"@lsn",rb_ary_new3(2,
2062
+ INT2FIX(t->lsn.file),
2063
+ INT2FIX(t->lsn.offset)));
2064
+ /* XA status is currently excluded */
2065
+ return ao;
2066
+ }
2067
+
2068
+ /*
2069
+ * call-seq:
2070
+ * db.stat(txn,flags) -> Bdb::Db::Stat
2071
+ *
2072
+ * get database status. Returns a Bdb::Db::Stat object that
2073
+ * is specialized to the db_type and only responds to [] to
2074
+ * retrieve status values. All values are stored in instance
2075
+ * variables, so singleton classes can be created and instance_eval
2076
+ * will work.
2077
+ */
2078
+ VALUE db_stat(VALUE obj, VALUE vtxn, VALUE vflags)
2079
+ {
2080
+ u_int32_t flags=0;
2081
+ int rv;
2082
+ t_dbh *dbh;
2083
+ t_txnh *txn=NULL;
2084
+ DBTYPE dbtype;
2085
+ union {
2086
+ void *stat;
2087
+ DB_HASH_STAT *hstat;
2088
+ DB_BTREE_STAT *bstat;
2089
+ DB_QUEUE_STAT *qstat;
2090
+ } su;
2091
+ VALUE s_obj;
2092
+
2093
+ if ( ! NIL_P(vflags) )
2094
+ flags=NUM2UINT(vflags);
2095
+ if ( ! NIL_P(vtxn) ) {
2096
+ Data_Get_Struct(vtxn,t_txnh,txn);
2097
+ if (!txn->txn)
2098
+ raise(0, "txn is closed");
2099
+ }
2100
+
2101
+ Data_Get_Struct(obj,t_dbh,dbh);
2102
+ if (!dbh->db)
2103
+ raise(0, "db is closed");
2104
+
2105
+ rv=dbh->db->get_type(dbh->db,&dbtype);
2106
+ if (rv)
2107
+ raise_error(rv,"db_stat %s",db_strerror(rv));
2108
+ #if DB_VERSION_MINOR > 2
2109
+ rv=dbh->db->stat(dbh->db,txn?txn->txn:NULL,&(su.stat),flags);
2110
+ #else
2111
+ rv=dbh->db->stat(dbh->db,&(su.stat),flags);
2112
+ #endif
2113
+ if (rv)
2114
+ raise_error(rv,"db_stat %s",db_strerror(rv));
2115
+
2116
+ s_obj=rb_class_new_instance(0,NULL,cDbStat);
2117
+ rb_iv_set(s_obj,"@dbtype",INT2FIX(dbtype));
2118
+
2119
+ switch(dbtype) {
2120
+
2121
+ #define hs_int(field) \
2122
+ rb_iv_set(s_obj,"@" #field,INT2FIX(su.hstat->field))
2123
+
2124
+ case DB_HASH:
2125
+ hs_int(hash_magic);
2126
+ hs_int(hash_version); /* Version number. */
2127
+ hs_int(hash_metaflags); /* Metadata flags. */
2128
+ hs_int(hash_nkeys); /* Number of unique keys. */
2129
+ hs_int(hash_ndata); /* Number of data items. */
2130
+ hs_int(hash_pagesize); /* Page size. */
2131
+ hs_int(hash_ffactor); /* Fill factor specified at create. */
2132
+ hs_int(hash_buckets); /* Number of hash buckets. */
2133
+ hs_int(hash_free); /* Pages on the free list. */
2134
+ hs_int(hash_bfree); /* Bytes free on bucket pages. */
2135
+ hs_int(hash_bigpages); /* Number of big key/data pages. */
2136
+ hs_int(hash_big_bfree); /* Bytes free on big item pages. */
2137
+ hs_int(hash_overflows); /* Number of overflow pages. */
2138
+ hs_int(hash_ovfl_free); /* Bytes free on ovfl pages. */
2139
+ hs_int(hash_dup); /* Number of dup pages. */
2140
+ hs_int(hash_dup_free); /* Bytes free on duplicate pages. */
2141
+ break;
2142
+
2143
+ #define bs_int(field) \
2144
+ rb_iv_set(s_obj,"@" #field,INT2FIX(su.bstat->field))
2145
+
2146
+ case DB_BTREE:
2147
+ case DB_RECNO:
2148
+ bs_int(bt_magic); /* Magic number. */
2149
+ bs_int(bt_version); /* Version number. */
2150
+ bs_int(bt_metaflags); /* Metadata flags. */
2151
+ bs_int(bt_nkeys); /* Number of unique keys. */
2152
+ bs_int(bt_ndata); /* Number of data items. */
2153
+ bs_int(bt_pagesize); /* Page size. */
2154
+ #if DB_VERSION_MINOR < 4
2155
+ bs_int(bt_maxkey); /* Maxkey value. */
2156
+ #endif
2157
+ bs_int(bt_minkey); /* Minkey value. */
2158
+ bs_int(bt_re_len); /* Fixed-length record length. */
2159
+ bs_int(bt_re_pad); /* Fixed-length record pad. */
2160
+ bs_int(bt_levels); /* Tree levels. */
2161
+ bs_int(bt_int_pg); /* Internal pages. */
2162
+ bs_int(bt_leaf_pg); /* Leaf pages. */
2163
+ bs_int(bt_dup_pg); /* Duplicate pages. */
2164
+ bs_int(bt_over_pg); /* Overflow pages. */
2165
+ #if DB_VERSION_MINOR > 2
2166
+ bs_int(bt_empty_pg); /* Empty pages. */
2167
+ #endif
2168
+ bs_int(bt_free); /* Pages on the free list. */
2169
+ bs_int(bt_int_pgfree); /* Bytes free in internal pages. */
2170
+ bs_int(bt_leaf_pgfree); /* Bytes free in leaf pages. */
2171
+ bs_int(bt_dup_pgfree); /* Bytes free in duplicate pages. */
2172
+ bs_int(bt_over_pgfree); /* Bytes free in overflow pages. */
2173
+
2174
+ break;
2175
+
2176
+ #define qs_int(field) \
2177
+ rb_iv_set(s_obj,"@" #field,INT2FIX(su.qstat->field))
2178
+
2179
+ case DB_QUEUE:
2180
+ qs_int(qs_magic); /* Magic number. */
2181
+ qs_int(qs_version); /* Version number. */
2182
+ qs_int(qs_metaflags); /* Metadata flags. */
2183
+ qs_int(qs_nkeys); /* Number of unique keys. */
2184
+ qs_int(qs_ndata); /* Number of data items. */
2185
+ qs_int(qs_pagesize); /* Page size. */
2186
+ qs_int(qs_extentsize); /* Pages per extent. */
2187
+ qs_int(qs_pages); /* Data pages. */
2188
+ qs_int(qs_re_len); /* Fixed-length record length. */
2189
+ qs_int(qs_re_pad); /* Fixed-length record pad. */
2190
+ qs_int(qs_pgfree); /* Bytes free in data pages. */
2191
+ qs_int(qs_first_recno); /* First not deleted record. */
2192
+ qs_int(qs_cur_recno); /* Next available record number. */
2193
+
2194
+ break;
2195
+ case DB_UNKNOWN:
2196
+ break;
2197
+ }
2198
+
2199
+ free(su.stat);
2200
+ return s_obj;
2201
+ }
2202
+
2203
+ /*
2204
+ * call-seq:
2205
+ * stat[name] -> value
2206
+ *
2207
+ * return status value
2208
+ */
2209
+ VALUE stat_aref(VALUE obj, VALUE vname)
2210
+ {
2211
+ return rb_iv_get(obj,RSTRING_PTR(rb_str_concat(rb_str_new2("@"),vname)));
2212
+ }
2213
+
2214
+ /*
2215
+ * call-seq:
2216
+ * env.txn_stat -> Bdb::TxnStat
2217
+ *
2218
+ * get the environment transaction status. Each active
2219
+ * transaction will be contained within a Bdb::TxnStat::Active
2220
+ * class.
2221
+ */
2222
+ VALUE env_txn_stat(VALUE obj, VALUE vflags)
2223
+ {
2224
+ u_int32_t flags=0;
2225
+ int rv;
2226
+ t_envh *eh;
2227
+ DB_TXN_STAT *statp;
2228
+ VALUE s_obj;
2229
+ VALUE active;
2230
+ int i;
2231
+
2232
+ if ( ! NIL_P(vflags))
2233
+ flags=NUM2UINT(vflags);
2234
+
2235
+ Data_Get_Struct(obj,t_envh,eh);
2236
+ if (!eh->env)
2237
+ raise(0, "env is closed");
2238
+
2239
+ /* statp will need free() */
2240
+ rv=eh->env->txn_stat(eh->env,&statp,flags);
2241
+ if ( rv != 0 ) {
2242
+ raise_error(rv, "txn_stat: %s",db_strerror(rv));
2243
+ }
2244
+
2245
+ s_obj=rb_class_new_instance(0,NULL,cTxnStat);
2246
+ rb_iv_set(s_obj,"@st_last_ckp",
2247
+ rb_ary_new3(2,
2248
+ INT2FIX(statp->st_last_ckp.file),
2249
+ INT2FIX(statp->st_last_ckp.offset)) );
2250
+ rb_iv_set(s_obj,"@st_time_ckp",
2251
+ rb_time_new(statp->st_time_ckp,0));
2252
+ rb_iv_set(s_obj,"@st_last_txnid",
2253
+ INT2FIX(statp->st_last_txnid));
2254
+ rb_iv_set(s_obj,"@st_maxtxns",
2255
+ INT2FIX(statp->st_maxtxns));
2256
+ rb_iv_set(s_obj,"@st_nactive",
2257
+ INT2FIX(statp->st_nactive));
2258
+ rb_iv_set(s_obj,"@st_maxnactive",
2259
+ INT2FIX(statp->st_maxnactive));
2260
+ rb_iv_set(s_obj,"@st_nbegins",
2261
+ INT2FIX(statp->st_nbegins));
2262
+ rb_iv_set(s_obj,"@st_naborts",
2263
+ INT2FIX(statp->st_naborts));
2264
+ rb_iv_set(s_obj,"@st_ncommits",
2265
+ INT2FIX(statp->st_ncommits));
2266
+ rb_iv_set(s_obj,"@st_nrestores",
2267
+ INT2FIX(statp->st_nrestores));
2268
+ rb_iv_set(s_obj,"@st_regsize",
2269
+ INT2FIX(statp->st_regsize));
2270
+ rb_iv_set(s_obj,"@st_region_wait",
2271
+ INT2FIX(statp->st_region_wait));
2272
+ rb_iv_set(s_obj,"@st_region_nowait",
2273
+ INT2FIX(statp->st_region_nowait));
2274
+ rb_iv_set(s_obj,"@st_txnarray",
2275
+ active=rb_ary_new2(statp->st_nactive));
2276
+
2277
+ for (i=0; i<statp->st_nactive; i++) {
2278
+ rb_ary_push(active,env_txn_stat_active(&(statp->st_txnarray[i])));
2279
+ }
2280
+
2281
+ free(statp);
2282
+ return s_obj;
2283
+ }
2284
+
2285
+ /*
2286
+ * call-seq:
2287
+ * env.set_timeout(timeout,flags) -> timeout
2288
+ *
2289
+ * set lock and transaction timeout
2290
+ */
2291
+ VALUE env_set_timeout(VALUE obj, VALUE vtimeout, VALUE vflags)
2292
+ {
2293
+ t_envh *eh;
2294
+ u_int32_t flags=0;
2295
+ db_timeout_t timeout;
2296
+ int rv;
2297
+
2298
+ if ( ! NIL_P(vflags))
2299
+ flags=NUM2UINT(vflags);
2300
+ timeout=FIX2UINT(vtimeout);
2301
+
2302
+ Data_Get_Struct(obj,t_envh,eh);
2303
+ if (!eh->env)
2304
+ raise(0, "env is closed");
2305
+ rv=eh->env->set_timeout(eh->env,timeout,flags);
2306
+ if ( rv != 0 ) {
2307
+ raise_error(rv, "env_set_timeout: %s",db_strerror(rv));
2308
+ }
2309
+
2310
+ return vtimeout;
2311
+ }
2312
+
2313
+ /*
2314
+ * call-seq:
2315
+ * env.get_timeout(flags) -> Fixnum
2316
+ *
2317
+ * Get current transaction and lock timeout value
2318
+ */
2319
+ VALUE env_get_timeout(VALUE obj, VALUE vflags)
2320
+ {
2321
+ t_envh *eh;
2322
+ u_int32_t flags=0;
2323
+ db_timeout_t timeout;
2324
+ int rv;
2325
+
2326
+ if ( ! NIL_P(vflags))
2327
+ flags=NUM2UINT(vflags);
2328
+
2329
+ Data_Get_Struct(obj,t_envh,eh);
2330
+ if (!eh->env)
2331
+ raise(0, "env is closed");
2332
+ rv=eh->env->get_timeout(eh->env,&timeout,flags);
2333
+ if ( rv != 0 ) {
2334
+ raise_error(rv, "env_get_timeout: %s",db_strerror(rv));
2335
+ }
2336
+
2337
+ return INT2FIX(timeout);
2338
+ }
2339
+
2340
+ /*
2341
+ * call-seq:
2342
+ * env.set_tx_max(max) -> max
2343
+ *
2344
+ * Set the maximum number of transactions with the environment
2345
+ */
2346
+ VALUE env_set_tx_max(VALUE obj, VALUE vmax)
2347
+ {
2348
+ t_envh *eh;
2349
+ u_int32_t max;
2350
+ int rv;
2351
+
2352
+ max=FIX2UINT(vmax);
2353
+
2354
+ Data_Get_Struct(obj,t_envh,eh);
2355
+ if (!eh->env)
2356
+ raise(0, "env is closed");
2357
+ rv=eh->env->set_tx_max(eh->env,max);
2358
+ if ( rv != 0 ) {
2359
+ raise_error(rv, "env_set_tx_max: %s",db_strerror(rv));
2360
+ }
2361
+
2362
+ return vmax;
2363
+ }
2364
+
2365
+ /*
2366
+ * call-seq
2367
+ * env.get_tx_max -> Fixnum
2368
+ *
2369
+ * Get current maximum number of transactions
2370
+ */
2371
+ VALUE env_get_tx_max(VALUE obj)
2372
+ {
2373
+ t_envh *eh;
2374
+ u_int32_t max;
2375
+ int rv;
2376
+
2377
+ Data_Get_Struct(obj,t_envh,eh);
2378
+ if (!eh->env)
2379
+ raise(0, "env is closed");
2380
+ rv=eh->env->get_tx_max(eh->env,&max);
2381
+ if ( rv != 0 ) {
2382
+ raise_error(rv, "env_get_tx_max: %s",db_strerror(rv));
2383
+ }
2384
+
2385
+ return INT2FIX(max);
2386
+ }
2387
+
2388
+ /*
2389
+ * call-seq:
2390
+ * env.mutex_set_max(max) -> max
2391
+ *
2392
+ * Set the maximum number of mutexes with the environment
2393
+ */
2394
+ VALUE env_mutex_set_max(VALUE obj, VALUE vmax)
2395
+ {
2396
+ t_envh *eh;
2397
+ u_int32_t max;
2398
+ int rv;
2399
+
2400
+ max=FIX2UINT(vmax);
2401
+
2402
+ Data_Get_Struct(obj,t_envh,eh);
2403
+ if (!eh->env)
2404
+ raise(0, "env is closed");
2405
+ rv=eh->env->mutex_set_max(eh->env,max);
2406
+ if ( rv != 0 ) {
2407
+ raise_error(rv, "env_mutex_set_max: %s",db_strerror(rv));
2408
+ }
2409
+
2410
+ return vmax;
2411
+ }
2412
+
2413
+ /*
2414
+ * call-seq
2415
+ * env.mutex_get_max -> Fixnum
2416
+ *
2417
+ * Get current maximum number of mutexes.
2418
+ */
2419
+ VALUE env_mutex_get_max(VALUE obj)
2420
+ {
2421
+ t_envh *eh;
2422
+ u_int32_t max;
2423
+ int rv;
2424
+
2425
+ Data_Get_Struct(obj,t_envh,eh);
2426
+ if (!eh->env)
2427
+ raise(0, "env is closed");
2428
+ rv=eh->env->mutex_get_max(eh->env,&max);
2429
+ if ( rv != 0 ) {
2430
+ raise_error(rv, "env_mutex_get_max: %s",db_strerror(rv));
2431
+ }
2432
+
2433
+ return INT2FIX(max);
2434
+ }
2435
+
2436
+ /*
2437
+ * call-seq:
2438
+ * env.set_shm_key(key) -> max
2439
+ *
2440
+ * Set the shared memory key base
2441
+ */
2442
+ VALUE env_set_shm_key(VALUE obj, VALUE vkey)
2443
+ {
2444
+ t_envh *eh;
2445
+ long key;
2446
+ int rv;
2447
+
2448
+ key=FIX2UINT(vkey);
2449
+
2450
+ Data_Get_Struct(obj,t_envh,eh);
2451
+ if (!eh->env)
2452
+ raise(0, "env is closed");
2453
+ rv=eh->env->set_shm_key(eh->env,key);
2454
+ if ( rv != 0 ) {
2455
+ raise_error(rv, "env_set_shm_key: %s",db_strerror(rv));
2456
+ }
2457
+
2458
+ return vkey;
2459
+ }
2460
+
2461
+ /*
2462
+ * call-seq
2463
+ * env.get_shm_key -> Fixnum
2464
+ *
2465
+ * Get the current shm key base
2466
+ */
2467
+ VALUE env_get_shm_key(VALUE obj)
2468
+ {
2469
+ t_envh *eh;
2470
+ long key;
2471
+ int rv;
2472
+
2473
+ Data_Get_Struct(obj,t_envh,eh);
2474
+ if (!eh->env)
2475
+ raise(0, "env is closed");
2476
+ rv=eh->env->get_shm_key(eh->env,&key);
2477
+ if ( rv != 0 ) {
2478
+ raise_error(rv, "env_get_shm_key: %s",db_strerror(rv));
2479
+ }
2480
+
2481
+ return INT2FIX(key);
2482
+ }
2483
+
2484
+ VALUE env_log_set_config_h(VALUE obj, u_int32_t flags, VALUE onoff) {
2485
+ t_envh *eh;
2486
+ int rv;
2487
+ Data_Get_Struct(obj,t_envh, eh);
2488
+ rv=eh->env->log_set_config(eh->env, flags, Qnil != flags && Qfalse != onoff);
2489
+ if(rv != 0)
2490
+ raise_error(rv, "log_set_config: %s", db_strerror(rv));
2491
+ return flags;
2492
+ }
2493
+
2494
+ VALUE env_log_get_config_h( VALUE obj, u_int32_t flags) {
2495
+ t_envh *eh;
2496
+ int rv, onoff;
2497
+ Data_Get_Struct(obj,t_envh, eh);
2498
+ rv=eh->env->log_get_config(eh->env, flags, &onoff);
2499
+ if(rv != 0)
2500
+ raise_error(rv, "log_set_config: %s", db_strerror(rv));
2501
+ return onoff ? Qtrue : Qfalse;
2502
+ }
2503
+
2504
+ #define ENV_LOG_CONFIG_FUNCS \
2505
+ ENV_LOG_CONFIG_FUNC(direct,DIRECT) \
2506
+ ENV_LOG_CONFIG_FUNC(dsync,DSYNC) \
2507
+ ENV_LOG_CONFIG_FUNC(auto_remove,AUTO_REMOVE) \
2508
+ ENV_LOG_CONFIG_FUNC(in_memory,IN_MEMORY) \
2509
+ ENV_LOG_CONFIG_FUNC(zero,ZERO)
2510
+
2511
+ #define ENV_LOG_CONFIG_FUNC( name, cnst) \
2512
+ VALUE env_log_set_##cnst( VALUE obj, VALUE flags) { \
2513
+ return env_log_set_config_h( obj, DB_LOG_##cnst, flags); \
2514
+ } \
2515
+ VALUE env_log_get_##cnst( VALUE obj, VALUE flags) { \
2516
+ return env_log_get_config_h( obj, DB_LOG_##cnst); \
2517
+ }
2518
+ ENV_LOG_CONFIG_FUNCS
2519
+
2520
+ VALUE env_log_set_config( VALUE obj, VALUE flags, VALUE onoff) {
2521
+ return env_log_set_config_h( obj, NUM2UINT(flags), onoff);
2522
+ }
2523
+
2524
+ /*
2525
+ * call-seq:
2526
+ * env.set_lk_detect(detect) -> detect
2527
+ *
2528
+ * Set when lock detector should be run
2529
+ */
2530
+ VALUE env_set_lk_detect(VALUE obj, VALUE vdetect)
2531
+ {
2532
+ t_envh *eh;
2533
+ u_int32_t detect;
2534
+ int rv;
2535
+
2536
+ detect=NUM2UINT(vdetect);
2537
+
2538
+ Data_Get_Struct(obj,t_envh,eh);
2539
+ if (!eh->env)
2540
+ raise(0, "env is closed");
2541
+ rv=eh->env->set_lk_detect(eh->env,detect);
2542
+ if ( rv != 0 ) {
2543
+ raise_error(rv, "env_set_lk_detect: %s",db_strerror(rv));
2544
+ }
2545
+
2546
+ return vdetect;
2547
+ }
2548
+
2549
+ /*
2550
+ * call-seq:
2551
+ * env.get_lk_detect() -> detect
2552
+ *
2553
+ * Get when lock detector should be run
2554
+ */
2555
+ VALUE env_get_lk_detect(VALUE obj)
2556
+ {
2557
+ t_envh *eh;
2558
+ u_int32_t detect;
2559
+ int rv;
2560
+
2561
+ Data_Get_Struct(obj,t_envh,eh);
2562
+ if (!eh->env)
2563
+ raise(0, "env is closed");
2564
+ rv=eh->env->get_lk_detect(eh->env,&detect);
2565
+ if ( rv != 0 ) {
2566
+ raise_error(rv, "env_set_lk_detect: %s",db_strerror(rv));
2567
+ }
2568
+
2569
+ return UINT2NUM(detect);
2570
+ }
2571
+
2572
+ /*
2573
+ * call-seq:
2574
+ * env.set_lk_max_locks(max) -> max
2575
+ *
2576
+ * Set the maximum number of locks in the environment
2577
+ */
2578
+ VALUE env_set_lk_max_locks(VALUE obj, VALUE vmax)
2579
+ {
2580
+ t_envh *eh;
2581
+ u_int32_t max;
2582
+ int rv;
2583
+
2584
+ max=FIX2UINT(vmax);
2585
+
2586
+ Data_Get_Struct(obj,t_envh,eh);
2587
+ if (!eh->env)
2588
+ raise(0, "env is closed");
2589
+ rv=eh->env->set_lk_max_locks(eh->env,max);
2590
+ if ( rv != 0 ) {
2591
+ raise_error(rv, "env_set_lk_max_locks: %s",db_strerror(rv));
2592
+ }
2593
+
2594
+ return vmax;
2595
+ }
2596
+
2597
+ /*
2598
+ * call-seq:
2599
+ * env.get_lk_max_locks -> max
2600
+ *
2601
+ * Get the maximum number of locks in the environment
2602
+ */
2603
+ VALUE env_get_lk_max_locks(VALUE obj)
2604
+ {
2605
+ t_envh *eh;
2606
+ u_int32_t max;
2607
+ int rv;
2608
+
2609
+ Data_Get_Struct(obj,t_envh,eh);
2610
+ if (!eh->env)
2611
+ raise(0, "env is closed");
2612
+ rv=eh->env->get_lk_max_locks(eh->env,&max);
2613
+ if ( rv != 0 ) {
2614
+ raise_error(rv, "env_get_lk_max_locks: %s",db_strerror(rv));
2615
+ }
2616
+
2617
+ return UINT2NUM(max);
2618
+ }
2619
+
2620
+ /*
2621
+ * call-seq:
2622
+ * env.set_lk_max_objects(max) -> max
2623
+ *
2624
+ * Set the maximum number of locks in the environment
2625
+ */
2626
+ VALUE env_set_lk_max_objects(VALUE obj, VALUE vmax)
2627
+ {
2628
+ t_envh *eh;
2629
+ u_int32_t max;
2630
+ int rv;
2631
+
2632
+ max=FIX2UINT(vmax);
2633
+
2634
+ Data_Get_Struct(obj,t_envh,eh);
2635
+ if (!eh->env)
2636
+ raise(0, "env is closed");
2637
+ rv=eh->env->set_lk_max_objects(eh->env,max);
2638
+ if ( rv != 0 ) {
2639
+ raise_error(rv, "env_set_lk_max_objects: %s",db_strerror(rv));
2640
+ }
2641
+
2642
+ return vmax;
2643
+ }
2644
+
2645
+ /*
2646
+ * call-seq:
2647
+ * env.get_lk_max_objects -> max
2648
+ *
2649
+ * Get the maximum number of locks in the environment
2650
+ */
2651
+ VALUE env_get_lk_max_objects(VALUE obj)
2652
+ {
2653
+ t_envh *eh;
2654
+ u_int32_t max;
2655
+ int rv;
2656
+
2657
+ Data_Get_Struct(obj,t_envh,eh);
2658
+ if (!eh->env)
2659
+ raise(0, "env is closed");
2660
+ rv=eh->env->get_lk_max_objects(eh->env,&max);
2661
+ if ( rv != 0 ) {
2662
+ raise_error(rv, "env_get_lk_max_objects: %s",db_strerror(rv));
2663
+ }
2664
+
2665
+ return UINT2NUM(max);
2666
+ }
2667
+
2668
+ VALUE env_report_stderr(VALUE obj)
2669
+ {
2670
+ t_envh *eh;
2671
+ //u_int32_t max;
2672
+ //int rv;
2673
+
2674
+ Data_Get_Struct(obj,t_envh,eh);
2675
+ if (!eh->env)
2676
+ raise(0, "env is closed");
2677
+ eh->env->set_errfile(eh->env,stderr);
2678
+
2679
+ return Qtrue;
2680
+ }
2681
+
2682
+ /*
2683
+ * call-seq:
2684
+ * env.set_data_dir(data_dir) -> data_dir
2685
+ *
2686
+ * set data_dir
2687
+ */
2688
+ VALUE env_set_data_dir(VALUE obj, VALUE vdata_dir)
2689
+ {
2690
+ t_envh *eh;
2691
+ const char *data_dir;
2692
+ int rv;
2693
+
2694
+ data_dir=StringValueCStr(vdata_dir);
2695
+
2696
+ Data_Get_Struct(obj,t_envh,eh);
2697
+ if (!eh->env)
2698
+ raise(0, "env is closed");
2699
+ rv=eh->env->set_data_dir(eh->env,data_dir);
2700
+ if ( rv != 0 ) {
2701
+ raise_error(rv, "env_set_data_dir: %s",db_strerror(rv));
2702
+ }
2703
+
2704
+ return vdata_dir;
2705
+ }
2706
+
2707
+ /*
2708
+ * call-seq:
2709
+ * env.get_data_dir -> [data_dir_1, data_dir_2, ...]
2710
+ *
2711
+ * get data_dir
2712
+ */
2713
+ VALUE env_get_data_dirs(VALUE obj)
2714
+ {
2715
+ t_envh *eh;
2716
+ const char **data_dirs;
2717
+ int rv;
2718
+ int ln;
2719
+
2720
+ Data_Get_Struct(obj,t_envh,eh);
2721
+ if (!eh->env)
2722
+ raise(0, "env is closed");
2723
+ rv=eh->env->get_data_dirs(eh->env,&data_dirs);
2724
+ if ( rv != 0 ) {
2725
+ raise_error(rv, "env_get_data_dir: %s",db_strerror(rv));
2726
+ }
2727
+
2728
+ ln = (sizeof (data_dirs))/sizeof(data_dirs[0]);
2729
+ VALUE rb_data_dirs = rb_ary_new2(ln);
2730
+ int i;
2731
+ for (i=0; i<ln; i++) {
2732
+ rb_ary_push(rb_data_dirs, rb_str_new2(data_dirs[i]));
2733
+ }
2734
+
2735
+ return rb_data_dirs;
2736
+ }
2737
+
2738
+ /*
2739
+ * call-seq:
2740
+ * env.set_lg_dir(lg_dir) -> lg_dir
2741
+ *
2742
+ * set lg_dir
2743
+ */
2744
+ VALUE env_set_lg_dir(VALUE obj, VALUE vlg_dir)
2745
+ {
2746
+ t_envh *eh;
2747
+ const char *lg_dir;
2748
+ int rv;
2749
+
2750
+ lg_dir=StringValueCStr(vlg_dir);
2751
+
2752
+ Data_Get_Struct(obj,t_envh,eh);
2753
+ if (!eh->env)
2754
+ raise(0, "env is closed");
2755
+ rv=eh->env->set_lg_dir(eh->env,lg_dir);
2756
+ if ( rv != 0 ) {
2757
+ raise_error(rv, "env_set_lg_dir: %s",db_strerror(rv));
2758
+ }
2759
+
2760
+ return vlg_dir;
2761
+ }
2762
+
2763
+ /*
2764
+ * call-seq:
2765
+ * env.get_lg_dir -> lg_dir
2766
+ *
2767
+ * get lg_dir
2768
+ */
2769
+ VALUE env_get_lg_dir(VALUE obj)
2770
+ {
2771
+ t_envh *eh;
2772
+ const char *lg_dir;
2773
+ int rv;
2774
+
2775
+ Data_Get_Struct(obj,t_envh,eh);
2776
+ if (!eh->env)
2777
+ raise(0, "env is closed");
2778
+ rv=eh->env->get_lg_dir(eh->env,&lg_dir);
2779
+ if ( rv != 0 ) {
2780
+ raise_error(rv, "env_get_lg_dir: %s",db_strerror(rv));
2781
+ }
2782
+
2783
+ return rb_str_new2(lg_dir);
2784
+ }
2785
+
2786
+ /*
2787
+ * call-seq:
2788
+ * env.set_tmp_dir(tmp_dir) -> tmp_dir
2789
+ *
2790
+ * set tmp_dir
2791
+ */
2792
+ VALUE env_set_tmp_dir(VALUE obj, VALUE vtmp_dir)
2793
+ {
2794
+ t_envh *eh;
2795
+ const char *tmp_dir;
2796
+ int rv;
2797
+
2798
+ tmp_dir=StringValueCStr(vtmp_dir);
2799
+
2800
+ Data_Get_Struct(obj,t_envh,eh);
2801
+ if (!eh->env)
2802
+ raise(0, "env is closed");
2803
+ rv=eh->env->set_tmp_dir(eh->env,tmp_dir);
2804
+ if ( rv != 0 ) {
2805
+ raise_error(rv, "env_set_tmp_dir: %s",db_strerror(rv));
2806
+ }
2807
+
2808
+ return vtmp_dir;
2809
+ }
2810
+
2811
+ /*
2812
+ * call-seq:
2813
+ * env.get_tmp_dir -> tmp_dir
2814
+ *
2815
+ * get tmp_dir
2816
+ */
2817
+ VALUE env_get_tmp_dir(VALUE obj)
2818
+ {
2819
+ t_envh *eh;
2820
+ const char *tmp_dir;
2821
+ int rv;
2822
+
2823
+ Data_Get_Struct(obj,t_envh,eh);
2824
+ if (!eh->env)
2825
+ raise(0, "env is closed");
2826
+ rv=eh->env->get_tmp_dir(eh->env,&tmp_dir);
2827
+ if ( rv != 0 ) {
2828
+ raise_error(rv, "env_get_tmp_dir: %s",db_strerror(rv));
2829
+ }
2830
+
2831
+ return rb_str_new2(tmp_dir);
2832
+ }
2833
+
2834
+ /*
2835
+ * call-seq:
2836
+ * env.get_home -> home
2837
+ *
2838
+ * get home
2839
+ */
2840
+ VALUE env_get_home(VALUE obj)
2841
+ {
2842
+ t_envh *eh;
2843
+ const char *home;
2844
+ int rv;
2845
+
2846
+ Data_Get_Struct(obj,t_envh,eh);
2847
+ if (!eh->env)
2848
+ raise(0, "env is closed");
2849
+ rv=eh->env->get_home(eh->env,&home);
2850
+ if ( rv != 0 ) {
2851
+ raise_error(rv, "env_get_home: %s",db_strerror(rv));
2852
+ }
2853
+
2854
+ return rb_str_new2(home);
2855
+ }
2856
+
2857
+ /*
2858
+ * call-seq:
2859
+ * env.set_verbose(which, onoff)
2860
+ *
2861
+ * set verbose messages on or off
2862
+ */
2863
+ VALUE env_set_verbose(VALUE obj, VALUE which, VALUE onoff)
2864
+ {
2865
+ t_envh *eh;
2866
+ int rv;
2867
+
2868
+ Data_Get_Struct(obj,t_envh,eh);
2869
+ rv = eh->env->set_verbose(eh->env, NUM2UINT(which), RTEST(onoff));
2870
+
2871
+ if ( rv != 0 ) raise_error(rv, "env_set_verbose: %s",db_strerror(rv));
2872
+
2873
+ return Qtrue;
2874
+ }
2875
+
2876
+ /*
2877
+ * call-seq:
2878
+ * env.rep_priority = int
2879
+ *
2880
+ * specify how the replication manager will handle acknowledgement of replication messages
2881
+ */
2882
+ VALUE env_rep_set_priority(VALUE obj, VALUE priority)
2883
+ {
2884
+ t_envh *eh;
2885
+ int rv;
2886
+
2887
+ Data_Get_Struct(obj,t_envh,eh);
2888
+ rv = eh->env->rep_set_priority(eh->env, NUM2UINT(priority));
2889
+
2890
+ if ( rv != 0 ) raise_error(rv, "env_rep_set_priority: %s", db_strerror(rv));
2891
+ return priority;
2892
+ }
2893
+
2894
+ /*
2895
+ * call-seq:
2896
+ * env.rep_priority -> int
2897
+ *
2898
+ * returns the replication manager's acknowledgement policy
2899
+ */
2900
+ VALUE env_rep_get_priority(VALUE obj)
2901
+ {
2902
+ t_envh *eh;
2903
+ u_int32_t priority;
2904
+
2905
+ Data_Get_Struct(obj,t_envh,eh);
2906
+ eh->env->rep_get_priority(eh->env, &priority);
2907
+
2908
+ return INT2NUM(priority);
2909
+ }
2910
+
2911
+ /*
2912
+ * call-seq:
2913
+ * env.rep_nsites = int
2914
+ *
2915
+ * specify how the replication manager will handle acknowledgement of replication messages
2916
+ */
2917
+ VALUE env_rep_set_nsites(VALUE obj, VALUE nsites)
2918
+ {
2919
+ t_envh *eh;
2920
+ int rv;
2921
+
2922
+ Data_Get_Struct(obj,t_envh,eh);
2923
+ rv = eh->env->rep_set_nsites(eh->env, NUM2UINT(nsites));
2924
+
2925
+ if ( rv != 0 ) raise_error(rv, "env_rep_set_nsites: %s", db_strerror(rv));
2926
+ return nsites;
2927
+ }
2928
+
2929
+ /*
2930
+ * call-seq:
2931
+ * env.rep_nsites -> int
2932
+ *
2933
+ * returns the replication manager's acknowledgement policy
2934
+ */
2935
+ VALUE env_rep_get_nsites(VALUE obj)
2936
+ {
2937
+ t_envh *eh;
2938
+ u_int32_t nsites;
2939
+
2940
+ Data_Get_Struct(obj,t_envh,eh);
2941
+ eh->env->rep_get_nsites(eh->env, &nsites);
2942
+
2943
+ return INT2NUM(nsites);
2944
+ }
2945
+
2946
+
2947
+ /*
2948
+ * call-seq:
2949
+ * env.repmgr_set_local_site(host, port)
2950
+ *
2951
+ * specify the local site for the replication manager
2952
+ */
2953
+ VALUE env_repmgr_set_local_site(VALUE obj, VALUE host, VALUE port)
2954
+ {
2955
+ t_envh *eh;
2956
+ int rv;
2957
+
2958
+ Data_Get_Struct(obj,t_envh,eh);
2959
+ rv = eh->env->repmgr_set_local_site(eh->env, StringValuePtr(host), NUM2UINT(port), 0);
2960
+
2961
+ if ( rv != 0 ) raise_error(rv, "env_repmgr_set_local_site: %s", db_strerror(rv));
2962
+ return Qtrue;
2963
+ }
2964
+
2965
+ /*
2966
+ * call-seq:
2967
+ * env.repmgr_add_remote_site(host, port)
2968
+ *
2969
+ * add a remote for the replication manager
2970
+ */
2971
+ VALUE env_repmgr_add_remote_site(VALUE obj, VALUE host, VALUE port)
2972
+ {
2973
+ t_envh *eh;
2974
+ int rv;
2975
+ int eidp;
2976
+
2977
+ Data_Get_Struct(obj,t_envh,eh);
2978
+ rv = eh->env->repmgr_add_remote_site(eh->env, StringValuePtr(host), NUM2UINT(port), &eidp, 0);
2979
+
2980
+ if ( rv != 0 ) raise_error(rv, "env_repmgr_add_remote_site: %s", db_strerror(rv));
2981
+ return INT2NUM(eidp);
2982
+ }
2983
+
2984
+ /*
2985
+ * call-seq:
2986
+ * env.repmgr_ack_policy = int
2987
+ *
2988
+ * specify how the replication manager will handle acknowledgement of replication messages
2989
+ */
2990
+ VALUE env_repmgr_set_ack_policy(VALUE obj, VALUE policy)
2991
+ {
2992
+ t_envh *eh;
2993
+ int rv;
2994
+
2995
+ Data_Get_Struct(obj,t_envh,eh);
2996
+ rv = eh->env->repmgr_set_ack_policy(eh->env, NUM2INT(policy));
2997
+
2998
+ if ( rv != 0 ) raise_error(rv, "env_repmgr_set_ack_policy: %s", db_strerror(rv));
2999
+ return policy;
3000
+ }
3001
+
3002
+ /*
3003
+ * call-seq:
3004
+ * env.repmgr_ack_policy -> int
3005
+ *
3006
+ * returns the replication manager's acknowledgement policy
3007
+ */
3008
+ VALUE env_repmgr_get_ack_policy(VALUE obj)
3009
+ {
3010
+ t_envh *eh;
3011
+ int policy;
3012
+
3013
+ Data_Get_Struct(obj,t_envh,eh);
3014
+ eh->env->repmgr_get_ack_policy(eh->env, &policy);
3015
+
3016
+ return INT2NUM(policy);
3017
+ }
3018
+
3019
+ /*
3020
+ * call-seq:
3021
+ * env.repmgr_start(num_threads, flags)
3022
+ *
3023
+ * start the replication manager
3024
+ */
3025
+ VALUE env_repmgr_start(VALUE obj, VALUE num_threads, VALUE flags)
3026
+ {
3027
+ t_envh *eh;
3028
+ int rv;
3029
+
3030
+ Data_Get_Struct(obj,t_envh,eh);
3031
+ rv = eh->env->repmgr_start(eh->env, NUM2INT(num_threads), NUM2UINT(flags));
3032
+
3033
+ if ( rv != 0 ) raise_error(rv, "env_repmgr_start: %s", db_strerror(rv));
3034
+ return Qtrue;
3035
+ }
3036
+
3037
+ /*
3038
+ * call-seq:
3039
+ * env.repmgr_stat_print
3040
+ *
3041
+ * prints replication manager stats
3042
+ */
3043
+ VALUE env_repmgr_stat_print(VALUE obj, VALUE flags)
3044
+ {
3045
+ t_envh *eh;
3046
+ int rv;
3047
+
3048
+ Data_Get_Struct(obj,t_envh,eh);
3049
+ rv = eh->env->repmgr_stat_print(eh->env, NUM2UINT(flags));
3050
+
3051
+ if ( rv != 0 ) raise_error(rv, "env_repmgr_stat_print: %s", db_strerror(rv));
3052
+ return Qtrue;
3053
+ }
3054
+
3055
+ VALUE env_set_lg_bsize( VALUE obj, VALUE size) {
3056
+ t_envh *eh;
3057
+ int rv;
3058
+ Data_Get_Struct(obj, t_envh, eh);
3059
+ rv = eh->env->set_lg_bsize( eh->env, NUM2UINT( size));
3060
+ if ( rv != 0 )
3061
+ raise_error(rv, "env_set_lg_bsize: %s", db_strerror(rv));
3062
+ return size;
3063
+ }
3064
+
3065
+ VALUE env_get_lg_bsize( VALUE obj) {
3066
+ t_envh *eh;
3067
+ int rv;
3068
+ u_int32_t size;
3069
+ Data_Get_Struct( obj, t_envh, eh);
3070
+ rv = eh->env->get_lg_bsize( eh->env, &size);
3071
+ if ( rv != 0 )
3072
+ raise_error(rv, "env_get_lg_bsize: %s", db_strerror(rv));
3073
+ return UINT2FIX(size);
3074
+ }
3075
+
3076
+ VALUE env_set_lg_max( VALUE obj, VALUE size) {
3077
+ t_envh *eh;
3078
+ int rv;
3079
+ Data_Get_Struct(obj, t_envh, eh);
3080
+ rv = eh->env->set_lg_max( eh->env, NUM2UINT( size));
3081
+ if ( rv != 0 )
3082
+ raise_error(rv, "env_set_lg_max: %s", db_strerror(rv));
3083
+ return size;
3084
+ }
3085
+
3086
+ VALUE env_get_lg_max( VALUE obj) {
3087
+ t_envh *eh;
3088
+ int rv;
3089
+ u_int32_t size;
3090
+ Data_Get_Struct( obj, t_envh, eh);
3091
+ rv = eh->env->get_lg_max( eh->env, &size);
3092
+ if ( rv != 0 )
3093
+ raise_error(rv, "env_get_lg_max: %s", db_strerror(rv));
3094
+ return UINT2FIX(size);
3095
+ }
3096
+
3097
+ VALUE env_set_lg_regionmax( VALUE obj, VALUE size) {
3098
+ t_envh *eh;
3099
+ int rv;
3100
+ Data_Get_Struct(obj, t_envh, eh);
3101
+ rv = eh->env->set_lg_regionmax( eh->env, NUM2UINT( size));
3102
+ if ( rv != 0 )
3103
+ raise_error(rv, "env_set_lg_regionmax: %s", db_strerror(rv));
3104
+ return size;
3105
+ }
3106
+
3107
+ VALUE env_get_lg_regionmax( VALUE obj) {
3108
+ t_envh *eh;
3109
+ int rv;
3110
+ u_int32_t size;
3111
+ Data_Get_Struct( obj, t_envh, eh);
3112
+ rv = eh->env->get_lg_regionmax( eh->env, &size);
3113
+ if ( rv != 0 )
3114
+ raise_error(rv, "env_get_lg_regionmax: %s", db_strerror(rv));
3115
+ return UINT2FIX(size);
3116
+ }
3117
+
3118
+
3119
+ static void txn_finish(t_txnh *txn)
3120
+ {
3121
+ if ( RTEST(ruby_debug) )
3122
+ rb_warning("%s/%d %s 0x%p",__FILE__,__LINE__,"txn_finish",(void*)txn);
3123
+
3124
+ txn->txn=NULL;
3125
+ if (txn->env) {
3126
+ rb_ary_delete(txn->env->atxn,txn->self);
3127
+ txn->env=NULL;
3128
+ }
3129
+ }
3130
+
3131
+ /*
3132
+ * call-seq:
3133
+ * txn.commit(flags) -> true
3134
+ *
3135
+ * commit a transaction
3136
+ */
3137
+ VALUE txn_commit(VALUE obj, VALUE vflags)
3138
+ {
3139
+ t_txnh *txn=NULL;
3140
+ u_int32_t flags=0;
3141
+ int rv;
3142
+
3143
+ if ( ! NIL_P(vflags))
3144
+ flags=NUM2UINT(vflags);
3145
+
3146
+ Data_Get_Struct(obj,t_txnh,txn);
3147
+
3148
+ if (!txn->txn)
3149
+ return Qfalse;
3150
+
3151
+ rv=txn->txn->commit(txn->txn,flags);
3152
+ txn_finish(txn);
3153
+ if ( rv != 0 ) {
3154
+ raise_error(rv, "txn_commit: %s",db_strerror(rv));
3155
+ return Qnil;
3156
+ }
3157
+ return Qtrue;
3158
+ }
3159
+
3160
+ /*
3161
+ * call-seq:
3162
+ * txn.abort -> true
3163
+ *
3164
+ * abort a transaction
3165
+ */
3166
+ VALUE txn_abort(VALUE obj)
3167
+ {
3168
+ t_txnh *txn=NULL;
3169
+ int rv;
3170
+
3171
+ Data_Get_Struct(obj,t_txnh,txn);
3172
+
3173
+ if (!txn->txn)
3174
+ return Qfalse;
3175
+
3176
+ rv=txn->txn->abort(txn->txn);
3177
+ txn_finish(txn);
3178
+ if ( rv != 0 ) {
3179
+ raise_error(rv, "txn_abort: %s",db_strerror(rv));
3180
+ return Qnil;
3181
+ }
3182
+ return Qtrue;
3183
+ }
3184
+
3185
+ /*
3186
+ * call-seq:
3187
+ * txn.discard -> true
3188
+ *
3189
+ * discard a transaction. Since prepare is not yet supported,
3190
+ * I don't think this has much value.
3191
+ */
3192
+ VALUE txn_discard(VALUE obj)
3193
+ {
3194
+ t_txnh *txn=NULL;
3195
+ int rv;
3196
+
3197
+ Data_Get_Struct(obj,t_txnh,txn);
3198
+
3199
+ if (!txn->txn)
3200
+ raise_error(0,"txn is closed");
3201
+
3202
+ rv=txn->txn->discard(txn->txn,NOFLAGS);
3203
+ txn_finish(txn);
3204
+ if ( rv != 0 ) {
3205
+ raise_error(rv, "txn_abort: %s",db_strerror(rv));
3206
+ return Qnil;
3207
+ }
3208
+ return Qtrue;
3209
+ }
3210
+
3211
+ /*
3212
+ * call-seq:
3213
+ * txn.tid -> Fixnum
3214
+ *
3215
+ * return the transaction id, (named tid to not conflict with
3216
+ * ruby's id method)
3217
+ */
3218
+ VALUE txn_id(VALUE obj)
3219
+ {
3220
+ t_txnh *txn=NULL;
3221
+ int rv;
3222
+
3223
+ Data_Get_Struct(obj,t_txnh,txn);
3224
+ if (!txn->txn)
3225
+ raise_error(0,"txn is closed");
3226
+
3227
+ rv=txn->txn->id(txn->txn);
3228
+ return INT2FIX(rv);
3229
+ }
3230
+
3231
+ /*
3232
+ * call-seq:
3233
+ * tx.set_timeout(timeout,flags) -> true
3234
+ *
3235
+ * set transaction lock timeout
3236
+ */
3237
+ VALUE txn_set_timeout(VALUE obj, VALUE vtimeout, VALUE vflags)
3238
+ {
3239
+ t_txnh *txn=NULL;
3240
+ db_timeout_t timeout;
3241
+ u_int32_t flags=0;
3242
+ int rv;
3243
+
3244
+ if ( ! NIL_P(vflags))
3245
+ flags=NUM2UINT(vflags);
3246
+
3247
+ if ( ! FIXNUM_P(vtimeout) )
3248
+ raise_error(0,"timeout must be a fixed integer");
3249
+ timeout=FIX2UINT(vtimeout);
3250
+
3251
+ Data_Get_Struct(obj,t_txnh,txn);
3252
+
3253
+ if (!txn->txn)
3254
+ raise_error(0,"txn is closed");
3255
+
3256
+ rv=txn->txn->set_timeout(txn->txn,timeout,flags);
3257
+ if ( rv != 0 ) {
3258
+ raise_error(rv, "txn_set_timeout: %s",db_strerror(rv));
3259
+ return Qnil;
3260
+ }
3261
+ return Qtrue;
3262
+ }
3263
+
3264
+ /*
3265
+ * Document-class: Bdb
3266
+ *
3267
+ * Ruby library that wraps the Sleepycat Berkeley DB.
3268
+ *
3269
+ * Developed against 4.3/4.4. No support for prior versions.
3270
+ */
3271
+
3272
+ void Init_bdb() {
3273
+ fv_call=rb_intern("call");
3274
+ fv_uniq=rb_intern("uniq");
3275
+ fv_err_new=rb_intern("new");
3276
+ fv_err_code=rb_intern("@code");
3277
+ fv_err_msg=rb_intern("@message");
3278
+
3279
+ mBdb = rb_define_module("Bdb");
3280
+
3281
+ #include "bdb_aux._c"
3282
+
3283
+ cDb = rb_define_class_under(mBdb,"Db", rb_cObject);
3284
+ eDbError = rb_define_class_under(mBdb,"DbError",rb_eStandardError);
3285
+ #define eDbE_create(n,c) eDbE_##c = rb_define_class_under(mBdb, #c, eDbError);
3286
+ EXCEPTIONS_CREATE
3287
+
3288
+ rb_define_method(eDbError,"initialize",err_initialize,2);
3289
+ rb_define_method(eDbError,"code",err_code,0);
3290
+
3291
+ rb_define_const(cDb,"BTREE",INT2FIX((DBTYPE)(DB_BTREE)));
3292
+ rb_define_const(cDb,"HASH",INT2FIX((DBTYPE)(DB_HASH)));
3293
+ rb_define_const(cDb,"RECNO",INT2FIX((DBTYPE)(DB_RECNO)));
3294
+ rb_define_const(cDb,"QUEUE",INT2FIX((DBTYPE)(DB_QUEUE)));
3295
+ rb_define_const(cDb,"UNKNOWN",INT2FIX((DBTYPE)(DB_UNKNOWN)));
3296
+
3297
+ rb_define_alloc_func(cDb,db_alloc);
3298
+ rb_define_method(cDb,"initialize",db_initialize,0);
3299
+
3300
+ rb_define_method(cDb,"put",db_put,4);
3301
+ rb_define_method(cDb,"get",db_get,4);
3302
+ rb_define_method(cDb,"pget",db_pget,4);
3303
+ rb_define_method(cDb,"del",db_del,3);
3304
+ rb_define_method(cDb,"cursor",db_cursor,2);
3305
+ rb_define_method(cDb,"associate",db_associate,4);
3306
+ rb_define_method(cDb,"btree_compare=",db_btree_compare_set,1);
3307
+ rb_define_method(cDb,"re_len=",db_set_re_len,1);
3308
+ rb_define_method(cDb,"re_len",db_get_re_len,0);
3309
+ rb_define_method(cDb,"flags=",db_flags_set,1);
3310
+ rb_define_method(cDb,"flags",db_flags_get,0);
3311
+ rb_define_method(cDb,"open",db_open,6);
3312
+ rb_define_method(cDb,"close",db_close,1);
3313
+ rb_define_method(cDb,"[]",db_aget,1);
3314
+ rb_define_method(cDb,"[]=",db_aset,2);
3315
+ rb_define_method(cDb,"join",db_join,2);
3316
+ rb_define_method(cDb,"get_byteswapped",db_get_byteswapped,0);
3317
+ rb_define_method(cDb,"get_type",db_get_type,0);
3318
+ rb_define_method(cDb,"remove",db_remove,3);
3319
+ rb_define_method(cDb,"key_range",db_key_range,3);
3320
+ rb_define_method(cDb,"rename",db_rename,4);
3321
+ rb_define_method(cDb,"pagesize",db_pagesize,0);
3322
+ rb_define_method(cDb,"pagesize=",db_pagesize_set,1);
3323
+ rb_define_method(cDb,"h_ffactor",db_h_ffactor,0);
3324
+ rb_define_method(cDb,"h_ffactor=",db_h_ffactor_set,1);
3325
+ rb_define_method(cDb,"h_nelem",db_h_nelem,0);
3326
+ rb_define_method(cDb,"h_nelem=",db_h_nelem_set,1);
3327
+ rb_define_method(cDb,"stat",db_stat,2);
3328
+ cDbStat = rb_define_class_under(cDb,"Stat",rb_cObject);
3329
+ rb_define_method(cDbStat,"[]",stat_aref,1);
3330
+
3331
+ rb_define_method(cDb,"sync",db_sync,0);
3332
+ rb_define_method(cDb,"truncate",db_truncate,1);
3333
+
3334
+ #if DB_VERSION_MINOR > 3
3335
+ rb_define_method(cDb,"compact",db_compact,5);
3336
+ #endif
3337
+
3338
+ cCursor = rb_define_class_under(cDb,"Cursor",rb_cObject);
3339
+ rb_define_method(cCursor,"get",dbc_get,3);
3340
+ rb_define_method(cCursor,"pget",dbc_pget,3);
3341
+ rb_define_method(cCursor,"put",dbc_put,3);
3342
+ rb_define_method(cCursor,"close",dbc_close,0);
3343
+ rb_define_method(cCursor,"del",dbc_del,0);
3344
+ rb_define_method(cCursor,"count",dbc_count,0);
3345
+
3346
+ cEnv = rb_define_class_under(mBdb,"Env",rb_cObject);
3347
+ rb_define_singleton_method(cEnv,"new",env_new,1);
3348
+ rb_define_method(cEnv,"open",env_open,3);
3349
+ rb_define_method(cEnv,"close",env_close,0);
3350
+ rb_define_method(cEnv,"db",env_db,0);
3351
+ rb_define_method(cEnv,"cachesize=",env_set_cachesize,1);
3352
+ rb_define_method(cEnv,"cachesize",env_get_cachesize,0);
3353
+ rb_define_method(cEnv,"flags",env_get_flags,0);
3354
+ rb_define_method(cEnv,"flags_on=",env_set_flags_on,1);
3355
+ rb_define_method(cEnv,"flags_off=",env_set_flags_off,1);
3356
+ rb_define_method(cEnv,"list_dbs",env_list_dbs,0);
3357
+ rb_define_method(cEnv,"txn_begin",env_txn_begin,2);
3358
+ rb_define_method(cEnv,"txn_checkpoint",env_txn_checkpoint,3);
3359
+ rb_define_method(cEnv,"txn_stat",env_txn_stat,1);
3360
+ rb_define_method(cEnv,"timeout",env_set_timeout,2);
3361
+ rb_define_method(cEnv,"timeout",env_get_timeout,1);
3362
+ rb_define_method(cEnv,"mutex_get_max",env_mutex_get_max,0);
3363
+ rb_define_method(cEnv,"mutex_set_max",env_mutex_set_max,1);
3364
+ rb_define_method(cEnv,"tx_max=",env_set_tx_max,1);
3365
+ rb_define_method(cEnv,"tx_max",env_get_tx_max,0);
3366
+ rb_define_method(cEnv,"report_stderr",env_report_stderr,0);
3367
+ rb_define_method(cEnv,"lk_detect=",env_set_lk_detect,1);
3368
+ rb_define_method(cEnv,"lk_detect",env_get_lk_detect,0);
3369
+ rb_define_method(cEnv,"lk_max_locks=",env_set_lk_max_locks,1);
3370
+ rb_define_method(cEnv,"lk_max_locks",env_get_lk_max_locks,0);
3371
+ rb_define_method(cEnv,"lk_max_objects=",env_set_lk_max_objects,1);
3372
+ rb_define_method(cEnv,"lk_max_objects",env_get_lk_max_objects,0);
3373
+ rb_define_method(cEnv,"shm_key=",env_set_shm_key,1);
3374
+ rb_define_method(cEnv,"shm_key",env_get_shm_key,0);
3375
+ rb_define_method(cEnv,"log_config",env_log_set_config,2);
3376
+ #define ENV_LOG_CONFIG_FUNC(name,cnst) \
3377
+ rb_define_method(cEnv,"log_"#name "=",env_log_set_##cnst,1); \
3378
+ rb_define_method(cEnv,"log_"#name,env_log_get_##cnst,0);
3379
+ ENV_LOG_CONFIG_FUNCS
3380
+
3381
+ rb_define_method(cEnv,"data_dir=",env_set_data_dir,1);
3382
+ rb_define_method(cEnv,"data_dirs",env_get_data_dirs,0);
3383
+ rb_define_method(cEnv,"lg_dir=",env_set_lg_dir,1);
3384
+ rb_define_method(cEnv,"lg_dir",env_get_lg_dir,0);
3385
+ rb_define_method(cEnv,"tmp_dir=",env_set_tmp_dir,1);
3386
+ rb_define_method(cEnv,"tmp_dir",env_get_tmp_dir,0);
3387
+ rb_define_method(cEnv,"home",env_get_home,0);
3388
+ rb_define_method(cEnv,"set_verbose",env_set_verbose,2);
3389
+
3390
+ rb_define_method(cEnv,"rep_priority=", env_rep_set_priority, 1);
3391
+ rb_define_method(cEnv,"rep_priority", env_rep_get_priority, 0);
3392
+ rb_define_method(cEnv,"rep_nsites=", env_rep_set_nsites, 1);
3393
+ rb_define_method(cEnv,"rep_nsites", env_rep_get_nsites, 0);
3394
+ rb_define_method(cEnv,"repmgr_set_local_site", env_repmgr_set_local_site, 2);
3395
+ rb_define_method(cEnv,"repmgr_add_remote_site", env_repmgr_add_remote_site, 2);
3396
+ rb_define_method(cEnv,"repmgr_ack_policy=", env_repmgr_set_ack_policy, 1);
3397
+ rb_define_method(cEnv,"repmgr_ack_policy", env_repmgr_get_ack_policy, 0);
3398
+ rb_define_method(cEnv,"repmgr_start", env_repmgr_start, 2);
3399
+ rb_define_method(cEnv,"repmgr_stat_print", env_repmgr_stat_print, 1);
3400
+
3401
+ rb_define_method(cEnv,"lg_bsize=", env_set_lg_bsize, 1);
3402
+ rb_define_method(cEnv,"lg_bsize", env_get_lg_bsize, 0);
3403
+ rb_define_method(cEnv,"lg_max=", env_set_lg_max, 1);
3404
+ rb_define_method(cEnv,"lg_max", env_get_lg_max, 0);
3405
+ rb_define_method(cEnv,"lg_regionmax=", env_set_lg_regionmax, 1);
3406
+ rb_define_method(cEnv,"lg_regionmax", env_get_lg_regionmax, 0);
3407
+
3408
+ cTxnStat = rb_define_class_under(mBdb,"TxnStat",rb_cObject);
3409
+ rb_define_method(cTxnStat,"[]",stat_aref,1);
3410
+
3411
+ cTxnStatActive =
3412
+ rb_define_class_under(cTxnStat,"Active",rb_cObject);
3413
+ rb_define_method(cTxnStatActive,"[]",stat_aref,1);
3414
+
3415
+ cTxn = rb_define_class_under(mBdb,"Txn",rb_cObject);
3416
+ rb_define_method(cTxn,"commit",txn_commit,1);
3417
+ rb_define_method(cTxn,"abort",txn_abort,0);
3418
+ rb_define_method(cTxn,"discard",txn_discard,0);
3419
+ rb_define_method(cTxn,"tid",txn_id,0);
3420
+ rb_define_method(cTxn,"set_timeout",txn_set_timeout,2);
3421
+ }