tdb 0.1.0 → 0.2.0
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/GIT-VERSION-GEN +1 -1
- data/README +34 -2
- data/ext/tdb/extconf.rb +1 -0
- data/ext/tdb/lookup3.c +1 -0
- data/ext/tdb/tdb.c +80 -19
- data/lib/tdb.rb +14 -0
- data/lib/tdb/mt.rb +41 -0
- data/tdb.gemspec +1 -1
- data/test/test_tdb.rb +24 -0
- data/test/test_tdb_mt.rb +85 -0
- metadata +8 -4
data/GIT-VERSION-GEN
CHANGED
data/README
CHANGED
|
@@ -8,17 +8,40 @@ write to the same databases used by Samba!
|
|
|
8
8
|
== Features
|
|
9
9
|
|
|
10
10
|
* Concurrent reader and writer processes may safely operate on the
|
|
11
|
-
same file.
|
|
11
|
+
same file. This is great for MRI 1.8 and 1.9 where multi-core
|
|
12
|
+
performance is easiest to achieve with processes and not threads.
|
|
12
13
|
|
|
13
|
-
*
|
|
14
|
+
* Fork-safe, you may fork and share the same TDB object in your parent
|
|
15
|
+
and child processes.
|
|
16
|
+
|
|
17
|
+
* Releases the GVL for slow disk operations under Ruby 1.9 so
|
|
18
|
+
other threads can run (but not other TDB operations on the same file)
|
|
14
19
|
|
|
15
20
|
* Includes several {hash functions}[link:Hash_Functions.html]
|
|
16
21
|
not included by upstream TDB.
|
|
17
22
|
|
|
23
|
+
== Caveats
|
|
24
|
+
|
|
25
|
+
These caveats will be addressed upstream in
|
|
26
|
+
{TDB2}[http://mid.gmane.org/201008021002.47351.rusty@rustcorp.com.au]
|
|
27
|
+
|
|
28
|
+
* NOT native thread-safe by default, you MUST initialize your TDB
|
|
29
|
+
objects with <code>:threadsafe => true</code> or call
|
|
30
|
+
TDB#threadsafe! on each TDB object if you run with threads
|
|
31
|
+
under Ruby 1.9 (but not 1.8).
|
|
32
|
+
|
|
33
|
+
* Database size is limited to 4G, even on 64-bit systems.
|
|
34
|
+
|
|
35
|
+
* TDB should be created with an appropriate :hash_size for large databases
|
|
36
|
+
or performance will suffer.
|
|
37
|
+
|
|
18
38
|
== Install
|
|
19
39
|
|
|
20
40
|
The original tdb library from the {main site}[http://tdb.samba.org/] is
|
|
21
41
|
required. Debian users can just <code>apt-get install tdb-dev</code>.
|
|
42
|
+
Non-Debian users: building against upstream tdb 1.2.2 and 1.2.7 are
|
|
43
|
+
known to be broken, so installing tdb from the latest git is
|
|
44
|
+
recommended.
|
|
22
45
|
|
|
23
46
|
The library consists of a C extension so you'll need a C compiler
|
|
24
47
|
and Ruby development libraries/headers.
|
|
@@ -33,6 +56,15 @@ You may also install it via RubyGems on RubyGems.org:
|
|
|
33
56
|
|
|
34
57
|
gem install tdb
|
|
35
58
|
|
|
59
|
+
If you have a tdb installation in a non-standard prefix, you
|
|
60
|
+
will have to use:
|
|
61
|
+
|
|
62
|
+
gem install tdb -- --with-tdb-dir=$PFX
|
|
63
|
+
|
|
64
|
+
Or if you have a non-standard prefix that linkers normally do not search:
|
|
65
|
+
|
|
66
|
+
gem install tdb -- --with-tdb-dir=$PFX --with-dldflags=-Wl,-rpath=$PFX/lib
|
|
67
|
+
|
|
36
68
|
You can get the latest source via git from the following locations
|
|
37
69
|
(these versions may not be stable):
|
|
38
70
|
|
data/ext/tdb/extconf.rb
CHANGED
data/ext/tdb/lookup3.c
CHANGED
data/ext/tdb/tdb.c
CHANGED
|
@@ -158,7 +158,7 @@ static VALUE nogvl_open(void *ptr)
|
|
|
158
158
|
return (VALUE)tdb;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
static void set_args(struct open_args *o, VALUE opts)
|
|
161
|
+
static void set_args(VALUE self, struct open_args *o, VALUE opts)
|
|
162
162
|
{
|
|
163
163
|
VALUE tmp;
|
|
164
164
|
|
|
@@ -203,8 +203,40 @@ static void set_args(struct open_args *o, VALUE opts)
|
|
|
203
203
|
|
|
204
204
|
o->hash_fn = (tdb_hash_func)NUM2ULONG(num);
|
|
205
205
|
}
|
|
206
|
+
|
|
207
|
+
tmp = rb_hash_aref(opts, ID2SYM(rb_intern("threadsafe")));
|
|
208
|
+
if (RTEST(tmp))
|
|
209
|
+
rb_funcall(self, rb_intern("threadsafe!"), 0);
|
|
206
210
|
}
|
|
207
211
|
|
|
212
|
+
/*
|
|
213
|
+
* :call-seq:
|
|
214
|
+
*
|
|
215
|
+
* TDB.new("/path/to/file") -> TDB
|
|
216
|
+
* TDB.new("/path/to/file", :hash_size => 666) -> TDB
|
|
217
|
+
* TDB.new("/path/to/file", :hash => :murmur2) -> TDB
|
|
218
|
+
* TDB.new("/path/to/file", :open_flags => IO::RDONLY) -> TDB
|
|
219
|
+
* TDB.new("/path/to/file", :tdb_flags => TDB::NOSYNC) -> TDB
|
|
220
|
+
*
|
|
221
|
+
* Initializes a TDB context. It takes several options.
|
|
222
|
+
*
|
|
223
|
+
* :hash_size - the number of buckets, this is the most important tuning
|
|
224
|
+
* parameter when creating large databases. This parameter only affects
|
|
225
|
+
* the creation of new databases.
|
|
226
|
+
*
|
|
227
|
+
* :open_flags - a bit mask of IO flags passed directly to open(2),
|
|
228
|
+
* File.open-compatible flags are accepted.
|
|
229
|
+
*
|
|
230
|
+
* :hash - any of the hashes described in Hash_Functions.
|
|
231
|
+
* This must remain the same for all clients.
|
|
232
|
+
*
|
|
233
|
+
* :tdb_flags - a bitmask of any combination of TDB::CLEAR_IF_FIRST,
|
|
234
|
+
* TDB::INTERNAL, TDB::NOLOCK, TDB::NOMMAP, TDB::CONVERT,
|
|
235
|
+
* TDB::BIGENDIAN, TDB::NOSYNC, TDB::SEQNUM, TDB::VOLATILE,
|
|
236
|
+
* TDB::ALLOW_NESTING, TDB::DISALLOW_NESTING, TDB::INCOMPATIBLE_HASH
|
|
237
|
+
*
|
|
238
|
+
* :mode - octal mode mask passed to open(2)
|
|
239
|
+
*/
|
|
208
240
|
static VALUE init(int argc, VALUE *argv, VALUE self)
|
|
209
241
|
{
|
|
210
242
|
struct tdb_context *tdb = db(self, 0);
|
|
@@ -214,7 +246,7 @@ static VALUE init(int argc, VALUE *argv, VALUE self)
|
|
|
214
246
|
if (tdb)
|
|
215
247
|
rb_raise(rb_eRuntimeError, "TDB already initialized");
|
|
216
248
|
rb_scan_args(argc, argv, "11", &path, &opts);
|
|
217
|
-
set_args(&o, opts);
|
|
249
|
+
set_args(self, &o, opts);
|
|
218
250
|
|
|
219
251
|
if (NIL_P(path))
|
|
220
252
|
o.tdb_flags |= TDB_INTERNAL;
|
|
@@ -587,12 +619,39 @@ static VALUE lockall_unmark(VALUE self)
|
|
|
587
619
|
return Qtrue;
|
|
588
620
|
}
|
|
589
621
|
|
|
622
|
+
/*
|
|
623
|
+
* clears out the database
|
|
624
|
+
*/
|
|
625
|
+
static VALUE clear(VALUE self)
|
|
626
|
+
{
|
|
627
|
+
struct tdb_context *tdb = db(self, 1);
|
|
628
|
+
if ((int)my_tbr((rb_blocking_function_t *)tdb_wipe_all, tdb))
|
|
629
|
+
my_raise(tdb);
|
|
630
|
+
return self;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
#ifdef HAVE_TDB_REPACK
|
|
634
|
+
/* repacks a database to reduce fragmentation, available with tdb 1.2.x+ */
|
|
635
|
+
static VALUE repack(VALUE self)
|
|
636
|
+
{
|
|
637
|
+
struct tdb_context *tdb = db(self, 1);
|
|
638
|
+
if ((int)my_tbr((rb_blocking_function_t *)tdb_repack, tdb))
|
|
639
|
+
my_raise(tdb);
|
|
640
|
+
return self;
|
|
641
|
+
}
|
|
642
|
+
#endif /* HAVE_TDB_REPACK */
|
|
643
|
+
|
|
590
644
|
void Init_tdb_ext(void)
|
|
591
645
|
{
|
|
592
646
|
cTDB = rb_define_class("TDB", rb_cObject);
|
|
593
647
|
|
|
594
648
|
hashes = rb_hash_new();
|
|
595
|
-
|
|
649
|
+
|
|
650
|
+
/*
|
|
651
|
+
* Available hash functions, the key is the name of the hash
|
|
652
|
+
* and the value is a pointer for internal for usage.
|
|
653
|
+
*/
|
|
654
|
+
rb_define_const(cTDB, "HASHES", hashes);
|
|
596
655
|
|
|
597
656
|
rb_define_alloc_func(cTDB, alloc);
|
|
598
657
|
rb_include_module(cTDB, rb_mEnumerable);
|
|
@@ -626,55 +685,57 @@ void Init_tdb_ext(void)
|
|
|
626
685
|
rb_define_method(cTDB, "unlockall_read", unlockall_read, 0);
|
|
627
686
|
rb_define_method(cTDB, "lockall_mark", lockall_mark, 0);
|
|
628
687
|
rb_define_method(cTDB, "lockall_unmark", lockall_unmark, 0);
|
|
688
|
+
rb_define_method(cTDB, "clear", clear, 0);
|
|
689
|
+
#ifdef HAVE_TDB_REPACK
|
|
690
|
+
rb_define_method(cTDB, "repack", repack, 0);
|
|
691
|
+
#endif /* HAVE_TDB_REPACK */
|
|
629
692
|
|
|
630
693
|
init_errors();
|
|
631
694
|
init_hashes();
|
|
632
695
|
|
|
633
|
-
#define tdb_CONST(x) rb_define_const(cTDB, #x, UINT2NUM(TDB_##x))
|
|
634
|
-
|
|
635
696
|
/* just a readability place holder */
|
|
636
|
-
|
|
697
|
+
rb_define_const(cTDB, "DEFAULT", UINT2NUM(TDB_DEFAULT));
|
|
637
698
|
|
|
638
699
|
/* clear database if we are the only one with it open */
|
|
639
|
-
|
|
700
|
+
rb_define_const(cTDB, "CLEAR_IF_FIRST", UINT2NUM(TDB_CLEAR_IF_FIRST));
|
|
640
701
|
|
|
641
702
|
/* don't store on disk, use in-memory database */
|
|
642
|
-
|
|
703
|
+
rb_define_const(cTDB, "INTERNAL", UINT2NUM(TDB_INTERNAL));
|
|
643
704
|
|
|
644
705
|
/* don't do any locking */
|
|
645
|
-
|
|
706
|
+
rb_define_const(cTDB, "NOLOCK", UINT2NUM(TDB_NOLOCK));
|
|
646
707
|
|
|
647
708
|
/* don't use mmap */
|
|
648
|
-
|
|
709
|
+
rb_define_const(cTDB, "NOMMAP", UINT2NUM(TDB_NOMMAP));
|
|
649
710
|
|
|
650
711
|
/* convert endian (internal use) */
|
|
651
|
-
|
|
712
|
+
rb_define_const(cTDB, "CONVERT", UINT2NUM(TDB_CONVERT));
|
|
652
713
|
|
|
653
714
|
/* header is big-endian (internal use) */
|
|
654
|
-
|
|
715
|
+
rb_define_const(cTDB, "BIGENDIAN", UINT2NUM(TDB_BIGENDIAN));
|
|
655
716
|
|
|
656
717
|
/* don't use synchronous transactions */
|
|
657
|
-
|
|
718
|
+
rb_define_const(cTDB, "NOSYNC", UINT2NUM(TDB_NOSYNC));
|
|
658
719
|
|
|
659
720
|
/* maintain a sequence number */
|
|
660
|
-
|
|
721
|
+
rb_define_const(cTDB, "SEQNUM", UINT2NUM(TDB_SEQNUM));
|
|
661
722
|
|
|
662
723
|
/* Activate the per-hashchain freelist, default 5 */
|
|
663
|
-
|
|
724
|
+
rb_define_const(cTDB, "VOLATILE", UINT2NUM(TDB_VOLATILE));
|
|
664
725
|
|
|
665
726
|
#ifdef TDB_ALLOW_NESTING
|
|
666
727
|
/* Allow transactions to nest */
|
|
667
|
-
|
|
728
|
+
rb_define_const(cTDB, "ALLOW_NESTING", UINT2NUM(TDB_ALLOW_NESTING));
|
|
668
729
|
#endif
|
|
669
730
|
|
|
670
731
|
#ifdef TDB_DISALLOW_NESTING
|
|
671
732
|
/* Disallow transactions to nest */
|
|
672
|
-
|
|
733
|
+
rb_define_const(cTDB, "DISALLOW_NESTING", UINT2NUM(TDB_DISALLOW_NESTING));
|
|
673
734
|
#endif
|
|
674
735
|
|
|
675
736
|
#ifdef TDB_INCOMPATIBLE_HASH
|
|
676
|
-
/* Better hashing
|
|
677
|
-
|
|
737
|
+
/* Better hashing, but can't be opened by tdb < 1.2.6. */
|
|
738
|
+
rb_define_const(cTDB, "INCOMPATIBLE_HASH", UINT2NUM(TDB_INCOMPATIBLE_HASH));
|
|
678
739
|
#endif
|
|
679
740
|
}
|
|
680
741
|
|
data/lib/tdb.rb
CHANGED
|
@@ -1,2 +1,16 @@
|
|
|
1
1
|
# -*- encoding: binary -*-
|
|
2
2
|
require 'tdb_ext'
|
|
3
|
+
class TDB
|
|
4
|
+
autoload :MT, 'tdb/mt'
|
|
5
|
+
|
|
6
|
+
# makes the current TDB object thread-safe
|
|
7
|
+
def threadsafe!
|
|
8
|
+
extend MT
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# will return true when TDB::MT is included in TDB or the TDB
|
|
12
|
+
# object is extended by TDB
|
|
13
|
+
def threadsafe?
|
|
14
|
+
false
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/tdb/mt.rb
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
module TDB::MT
|
|
3
|
+
def initialize
|
|
4
|
+
super
|
|
5
|
+
@lock = Mutex.new
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
wrap_methods = %w(
|
|
9
|
+
close closed? fetch [] store []= insert! modify! insert modify
|
|
10
|
+
key? has_key? include? member?
|
|
11
|
+
nuke! delete
|
|
12
|
+
lockall trylockall unlockall
|
|
13
|
+
lockall_read trylockall_read unlockall_read
|
|
14
|
+
lockall_mark lockall_unmark
|
|
15
|
+
clear
|
|
16
|
+
)
|
|
17
|
+
wrap_methods << :repack if TDB.method_defined?(:repack)
|
|
18
|
+
wrap_methods.each do |meth|
|
|
19
|
+
eval "def #{meth}(*args); @lock.synchronize { super }; end"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def each(&block)
|
|
23
|
+
@lock.synchronize do
|
|
24
|
+
super { |k,v| @lock.exclusive_unlock { yield(k,v) } }
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def threadsafe?
|
|
29
|
+
true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.extended(obj)
|
|
33
|
+
obj.instance_eval { @lock = Mutex.new unless defined?(@lock) }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.included(klass)
|
|
37
|
+
ObjectSpace.each_object(klass) { |obj|
|
|
38
|
+
obj.instance_eval { @lock = Mutex.new unless defined?(@lock) }
|
|
39
|
+
}
|
|
40
|
+
end
|
|
41
|
+
end
|
data/tdb.gemspec
CHANGED
data/test/test_tdb.rb
CHANGED
|
@@ -257,4 +257,28 @@ class TestTdb < Test::Unit::TestCase
|
|
|
257
257
|
assert Process.waitpid2(pid)[1].success?
|
|
258
258
|
assert_equal true, @tdb.trylockall
|
|
259
259
|
end
|
|
260
|
+
|
|
261
|
+
def test_check_constant_typos
|
|
262
|
+
names = {}
|
|
263
|
+
TDB.constants.each { |const| names[const] = TDB.const_get(const) }
|
|
264
|
+
assert_equal TDB.constants.size, names.size
|
|
265
|
+
|
|
266
|
+
values = {}
|
|
267
|
+
TDB.constants.each { |const| values[TDB.const_get(const)] = const }
|
|
268
|
+
assert_equal TDB.constants.size, values.size
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def test_clear
|
|
272
|
+
@tdb = TDB.new(nil)
|
|
273
|
+
@tdb["hello"] = "world"
|
|
274
|
+
assert_equal @tdb, @tdb.clear
|
|
275
|
+
assert ! @tdb.include?("hello")
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def test_repack
|
|
279
|
+
@tdb = TDB.new(nil)
|
|
280
|
+
@tdb["hello"] = "world"
|
|
281
|
+
assert_equal @tdb, @tdb.repack
|
|
282
|
+
assert_equal "world", @tdb["hello"]
|
|
283
|
+
end if TDB.method_defined?(:repack)
|
|
260
284
|
end
|
data/test/test_tdb_mt.rb
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
$stdout.sync = $stderr.sync = true
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'tempfile'
|
|
5
|
+
$-w = true
|
|
6
|
+
require 'tdb'
|
|
7
|
+
|
|
8
|
+
class Test_TDB_MT < Test::Unit::TestCase
|
|
9
|
+
def setup
|
|
10
|
+
@tdb = @tmp = nil
|
|
11
|
+
@start_pid = $$
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def teardown
|
|
15
|
+
return if @start_pid != $$
|
|
16
|
+
@tmp.close! if @tmp.respond_to?(:close!)
|
|
17
|
+
@tdb.close if @tdb && ! @tdb.closed?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_make_threadsafe
|
|
21
|
+
@tdb = TDB.new(nil)
|
|
22
|
+
assert_kind_of TDB, @tdb
|
|
23
|
+
assert ! @tdb.threadsafe?
|
|
24
|
+
assert_nothing_raised { @tdb.threadsafe! }
|
|
25
|
+
assert @tdb.threadsafe?
|
|
26
|
+
@tdb.each { |k,v| assert_equal v, @tdb[k] }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_init_threadsafe
|
|
30
|
+
@tdb = TDB.new(nil, :threadsafe => true)
|
|
31
|
+
assert @tdb.threadsafe?
|
|
32
|
+
@tdb.close
|
|
33
|
+
@tdb = TDB.new(nil, :threadsafe => false)
|
|
34
|
+
assert ! @tdb.threadsafe?
|
|
35
|
+
@tdb.close
|
|
36
|
+
@tdb = TDB.new(nil)
|
|
37
|
+
assert ! @tdb.threadsafe?
|
|
38
|
+
@tdb.close
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_thread_safe_torture_test
|
|
42
|
+
@tdb = TDB.new(nil)
|
|
43
|
+
assert_nothing_raised { @tdb.threadsafe! }
|
|
44
|
+
pid = fork do
|
|
45
|
+
Thread.abort_on_exception = true
|
|
46
|
+
threads = []
|
|
47
|
+
blob = 'foo' * 1000
|
|
48
|
+
nr = 10000
|
|
49
|
+
t = Thread.new do
|
|
50
|
+
while true
|
|
51
|
+
Thread.pass
|
|
52
|
+
@tdb.to_a
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
threads << Thread.new { nr.times { |i| @tdb[i.to_s] = blob } }
|
|
56
|
+
threads << Thread.new { nr.times { |i| @tdb[i.to_s] = blob } }
|
|
57
|
+
threads << Thread.new { nr.times { |i| @tdb[i.to_s] = blob } }
|
|
58
|
+
threads << Thread.new { nr.times { |i| @tdb[i.to_s] = blob } }
|
|
59
|
+
threads << t
|
|
60
|
+
|
|
61
|
+
t.kill
|
|
62
|
+
threads.each { |t| t.join }
|
|
63
|
+
end
|
|
64
|
+
_, status = Process.waitpid2(pid)
|
|
65
|
+
assert status.success?, status.inspect
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def test_check_methods
|
|
69
|
+
m = TDB.instance_methods.sort
|
|
70
|
+
m -= Object.instance_methods
|
|
71
|
+
m -= Enumerable.instance_methods
|
|
72
|
+
m.map! { |x| x.to_sym }
|
|
73
|
+
mt = TDB::MT.instance_methods.sort
|
|
74
|
+
m -= [ :threadsafe! ]
|
|
75
|
+
m += [ :include?, :member? ]
|
|
76
|
+
m.sort!
|
|
77
|
+
unwrapped = ( (m - mt) | (mt - m)).uniq
|
|
78
|
+
assert unwrapped.empty?, "unwrapped methods: #{unwrapped.inspect}"
|
|
79
|
+
@tdb = TDB.new(nil)
|
|
80
|
+
respond_to?(:refute_match) and
|
|
81
|
+
m.each { |meth| refute_match(/\bTDB::MT\b/, @tdb.method(meth).to_s) }
|
|
82
|
+
@tdb.threadsafe!
|
|
83
|
+
m.each { |meth| assert_match(/\bTDB::MT\b/, @tdb.method(meth).to_s) }
|
|
84
|
+
end
|
|
85
|
+
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tdb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 23
|
|
5
5
|
prerelease: false
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
|
-
-
|
|
8
|
+
- 2
|
|
9
9
|
- 0
|
|
10
|
-
version: 0.
|
|
10
|
+
version: 0.2.0
|
|
11
11
|
platform: ruby
|
|
12
12
|
authors:
|
|
13
13
|
- Ruby tdb hackers
|
|
@@ -15,7 +15,7 @@ autorequire:
|
|
|
15
15
|
bindir: bin
|
|
16
16
|
cert_chain: []
|
|
17
17
|
|
|
18
|
-
date: 2010-12-
|
|
18
|
+
date: 2010-12-08 00:00:00 +00:00
|
|
19
19
|
default_executable:
|
|
20
20
|
dependencies: []
|
|
21
21
|
|
|
@@ -37,6 +37,7 @@ extra_rdoc_files:
|
|
|
37
37
|
- NEWS
|
|
38
38
|
- ChangeLog
|
|
39
39
|
- lib/tdb.rb
|
|
40
|
+
- lib/tdb/mt.rb
|
|
40
41
|
- ext/tdb/tdb.c
|
|
41
42
|
files:
|
|
42
43
|
- .document
|
|
@@ -62,9 +63,11 @@ files:
|
|
|
62
63
|
- ext/tdb/rbtdb.h
|
|
63
64
|
- ext/tdb/tdb.c
|
|
64
65
|
- lib/tdb.rb
|
|
66
|
+
- lib/tdb/mt.rb
|
|
65
67
|
- setup.rb
|
|
66
68
|
- tdb.gemspec
|
|
67
69
|
- test/test_tdb.rb
|
|
70
|
+
- test/test_tdb_mt.rb
|
|
68
71
|
has_rdoc: true
|
|
69
72
|
homepage: http://bogomips.org/ruby-tdb/
|
|
70
73
|
licenses: []
|
|
@@ -102,4 +105,5 @@ signing_key:
|
|
|
102
105
|
specification_version: 3
|
|
103
106
|
summary: Trivial Database bindings for Ruby
|
|
104
107
|
test_files:
|
|
108
|
+
- test/test_tdb_mt.rb
|
|
105
109
|
- test/test_tdb.rb
|