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