sldb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,257 @@
1
+ URLS
2
+
3
+ http://raa.ruby-lang.org/search.rhtml?search=sldb
4
+ http://codeforpeople.com/lib/ruby/sldb
5
+
6
+ ABOUT
7
+
8
+ sldb is a multi-thread, multi-process, and nfs safe abstraction of sqlite
9
+ databases. the sldb module is a class generator for concrete databases. the
10
+ programmer is freed from worrying about 'database locked' errors and
11
+ transactions are automatically retried using a linear cyclical backoff time.
12
+ in the case where all access is via the generated class sldb can even detect
13
+ certain bugs in nfs daemons and auto-recover. the class is not limited to nfs
14
+ use whatsover and can be a useful way to use an embedded sql based databases
15
+ in your ruby code with minimal effort while still providing
16
+ multi-process/multi-thread concurrency - something which is quite difficult if
17
+ using the raw sqlite-ruby interface.
18
+
19
+ AUTHOR
20
+
21
+ ara [dot] t [dot] howard [at] noaa [dot] gov
22
+
23
+ SAMPLES
24
+
25
+ <========< sample/a.rb >========>
26
+
27
+ ~ > cat sample/a.rb
28
+
29
+ require 'sldb'
30
+
31
+ #
32
+ # use the factory method to specify your database class
33
+ #
34
+ DB =
35
+ SLDB::class {
36
+ schema 'create table t ( a, b, c )'
37
+ path 'sldb'
38
+ }
39
+
40
+ #
41
+ # create and instance and use it - it will be created and initialized with the
42
+ # schema on the first use
43
+ #
44
+ db = DB::new
45
+
46
+ db.transaction do
47
+ db.execute 'insert into t values (0,1,2)'
48
+ db.execute('select * from t'){|tuple| p tuple}
49
+ end
50
+
51
+
52
+ ~ > ruby sample/a.rb
53
+
54
+ ["0", "1", "2"]
55
+
56
+
57
+ <========< sample/b.rb >========>
58
+
59
+ ~ > cat sample/b.rb
60
+
61
+ require 'csv'
62
+ require 'sldb'
63
+
64
+ DB = SLDB::class :schema => 'create table t ( a, b, c )'
65
+ db = DB::new 'sldb'
66
+
67
+ #
68
+ # sldb uses arrayfields so many operations are natural since tuples are arrays,
69
+ # yet can be indexed by field
70
+ #
71
+ db.transaction do
72
+ db.execute "insert into t values ( 'A', 'B', 'C' )"
73
+ db.execute('select * from t') do |tuple|
74
+ puts "tuple => #{ tuple.inspect }"
75
+ tuple.fields.each{|f| puts " tuple[#{ f }] => #{ tuple[f] }"}
76
+ end
77
+ end
78
+
79
+ puts
80
+
81
+ #
82
+ # csv generation is an example of something which is much more natural with
83
+ # arrays
84
+ #
85
+ CSV::generate('csv') do |csv|
86
+ db.ro_transaction{db.execute('select * from t'){|t| csv << t}}
87
+ end
88
+ puts(IO::read('csv'))
89
+
90
+
91
+ ~ > ruby sample/b.rb
92
+
93
+ tuple => ["A", "B", "C"]
94
+ tuple[a] => A
95
+ tuple[b] => B
96
+ tuple[c] => C
97
+
98
+ A,B,C
99
+
100
+
101
+ <========< sample/c.rb >========>
102
+
103
+ ~ > cat sample/c.rb
104
+
105
+ require 'yaml'
106
+ require 'sldb'
107
+
108
+ DB = SLDB::new {
109
+ schema <<-sql
110
+ create table t0 ( a, b, c);
111
+ create table t1 ( x, y, z);
112
+ sql
113
+
114
+ path 'sldb'
115
+ }
116
+
117
+ db = DB::new
118
+
119
+ #
120
+ # many utility methods exist to make working with the databases easier
121
+ #
122
+ db.transaction do
123
+ db.tablenames.each do |tablename|
124
+ tuple = db.tuple_for tablename
125
+ tuple.fields.each{|f| tuple[f] = db.timestamp 'local' => true}
126
+ values = db.quote tuple
127
+ sql = "insert into #{ tablename } values (#{ values.join ',' })"
128
+ db.execute sql
129
+ end
130
+ end
131
+
132
+ db.read_only_transaction do
133
+ db.tablenames.each do |tablename|
134
+ db.execute("select * from #{ tablename }") do |t|
135
+ t.map!{|f| db.stamptime f, 'local' => true}
136
+ y t.to_hash
137
+ end
138
+ end
139
+ end
140
+
141
+ ~ > ruby sample/c.rb
142
+
143
+ ---
144
+ a: 2005-05-13 14:13:40.754680 -06:00
145
+ b: 2005-05-13 14:13:40.754882 -06:00
146
+ c: 2005-05-13 14:13:40.754910 -06:00
147
+ ---
148
+ x: 2005-05-13 14:13:40.755928 -06:00
149
+ y: 2005-05-13 14:13:40.755980 -06:00
150
+ z: 2005-05-13 14:13:40.756005 -06:00
151
+
152
+
153
+ <========< sample/d.rb >========>
154
+
155
+ ~ > cat sample/d.rb
156
+
157
+ require 'yaml'
158
+ require 'sldb'
159
+
160
+ DB = SLDB::new { schema 'create table t ( tid, time )'; path 'sldb' }
161
+ db = DB::new
162
+
163
+ #
164
+ # multi-processed/multi-threaded applications may simoultaneously access the db
165
+ #
166
+
167
+ 4.times do
168
+ unless fork
169
+ pid = $$
170
+ threads = []
171
+ 2.times do |i|
172
+ threads <<
173
+ Thread::new(i, db) do |tid, db|
174
+ sleep rand
175
+ tuple = db.tuple_for 't'
176
+ tuple['tid'] = "#{ pid }:#{ tid }"
177
+ tuple['time'] = Time::now.to_f
178
+ values = db.quote tuple
179
+ db.transaction{db.execute "insert into t values(#{ values.join ',' })"}
180
+ end
181
+ end
182
+ threads.each{|t| t.join}
183
+ exit
184
+ end
185
+ end
186
+
187
+ 4.times{ Process::wait }
188
+
189
+ report = Hash::new{|h,k| h[k] = []}
190
+
191
+ db.transaction{db.execute("select * from t"){|t| report['t'] << t.to_hash}}
192
+
193
+ y report
194
+
195
+ ~ > ruby sample/d.rb
196
+
197
+ ---
198
+ t:
199
+ -
200
+ time: "1116015221.16824"
201
+ tid: 9697:1
202
+ -
203
+ time: "1116015221.2326"
204
+ tid: 9697:0
205
+ -
206
+ time: "1116015221.64353"
207
+ tid: 9696:0
208
+ -
209
+ time: "1116015221.83744"
210
+ tid: 9695:0
211
+ -
212
+ time: "1116015221.85167"
213
+ tid: 9695:1
214
+ -
215
+ time: "1116015222.25714"
216
+ tid: 9698:0
217
+ -
218
+ time: "1116015222.27658"
219
+ tid: 9698:1
220
+ -
221
+ time: "1116015221.81659"
222
+ tid: 9696:1
223
+
224
+
225
+ <========< sample/e.rb >========>
226
+
227
+ ~ > cat sample/e.rb
228
+
229
+ require 'sldb'
230
+
231
+ #
232
+ # the SLDB factory method handles - as a special case - a pathname being passed
233
+ # in as meaning : create the class AND give me and instance of it which allows
234
+ # connecting to dbs even when the schema is unknown
235
+ #
236
+
237
+ dbklass = SLDB::new 'schema' => 'create table t ( answer )',
238
+ 'path' => 'sldb'
239
+ db = dbklass::new
240
+ db.transaction{ db.execute 'insert into t values ( 42 )' }
241
+
242
+ fork do
243
+ db = SLDB::new 'sldb' # here we don't know schema
244
+ db.transaction{ db.execute('select * from t'){|t| puts t['answer']}}
245
+ end
246
+
247
+ Process::wait
248
+
249
+ ~ > ruby sample/e.rb
250
+
251
+ 42
252
+
253
+
254
+ CAVEATS
255
+
256
+ this library is __highly__ experimental and subject to change.
257
+
@@ -0,0 +1,30 @@
1
+ URLS
2
+
3
+ http://raa.ruby-lang.org/search.rhtml?search=sldb
4
+ http://codeforpeople.com/lib/ruby/sldb
5
+
6
+ ABOUT
7
+
8
+ sldb is a multi-thread, multi-process, and nfs safe abstraction of sqlite
9
+ databases. the sldb module is a class generator for concrete databases. the
10
+ programmer is freed from worrying about 'database locked' errors and
11
+ transactions are automatically retried using a linear cyclical backoff time.
12
+ in the case where all access is via the generated class sldb can even detect
13
+ certain bugs in nfs daemons and auto-recover. the class is not limited to nfs
14
+ use whatsover and can be a useful way to use an embedded sql based databases
15
+ in your ruby code with minimal effort while still providing
16
+ multi-process/multi-thread concurrency - something which is quite difficult if
17
+ using the raw sqlite-ruby interface.
18
+
19
+ AUTHOR
20
+
21
+ ara [dot] t [dot] howard [at] noaa [dot] gov
22
+
23
+ SAMPLES
24
+
25
+ @samples
26
+
27
+ CAVEATS
28
+
29
+ this library is __highly__ experimental and subject to change.
30
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,23 @@
1
+ lib, version = File::basename(File::dirname(File::expand_path(__FILE__))).split %r/-/, 2
2
+
3
+ require 'rubygems'
4
+
5
+ Gem::Specification::new do |spec|
6
+ spec.name = lib
7
+ spec.version = version
8
+ spec.platform = Gem::Platform::RUBY
9
+ spec.summary = lib
10
+
11
+ spec.files = Dir::glob "**/**"
12
+ spec.executables = Dir::glob("bin/*").map{|exe| File::basename exe}
13
+
14
+ spec.require_path = "lib"
15
+ spec.autorequire = lib
16
+
17
+ spec.has_rdoc = File::exist? "doc"
18
+ spec.test_suite_file = "test/#{ lib }.rb" if File::directory? "test"
19
+
20
+ spec.author = "Ara T. Howard"
21
+ spec.email = "ara.t.howard@noaa.gov"
22
+ spec.homepage = "http://codeforpeople.com/lib/ruby/#{ lib }/"
23
+ end
@@ -0,0 +1,26 @@
1
+ $VERBOSE=nil
2
+ def indent s, n = 2
3
+ ws = ' ' * n
4
+ s.gsub %r/^/, ws
5
+ end
6
+
7
+ template = IO::read 'README.tmpl'
8
+
9
+ samples = ''
10
+ prompt = '~ > '
11
+
12
+ Dir['sample/*'].each do |sample|
13
+ samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
14
+ cmd = "cat #{ sample }"
15
+ samples << indent(prompt + cmd, 2) << "\n\n"
16
+ samples << indent(`#{ cmd }`, 4) << "\n"
17
+ cmd = "ruby #{ sample }"
18
+ samples << indent(prompt + cmd, 2) << "\n\n"
19
+ cmd = "rm -rf ./sldb; rm -rf csv; ruby -I ./lib #{ sample }"
20
+ samples << indent(`#{ cmd }`, 4) << "\n"
21
+ end
22
+
23
+ #samples.gsub! %r/^/, ' '
24
+
25
+ readme = template.gsub %r/^\s*@samples\s*$/, samples
26
+ print readme
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rbconfig'
3
+ require 'find'
4
+ require 'ftools'
5
+ require 'tempfile'
6
+ include Config
7
+
8
+ LIBDIR = "lib"
9
+ LIBDIR_MODE = 0644
10
+
11
+ BINDIR = "bin"
12
+ BINDIR_MODE = 0755
13
+
14
+
15
+ $srcdir = CONFIG["srcdir"]
16
+ $version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
17
+ $libdir = File.join(CONFIG["libdir"], "ruby", $version)
18
+ $archdir = File.join($libdir, CONFIG["arch"])
19
+ $site_libdir = $:.find {|x| x =~ /site_ruby$/}
20
+ $bindir = CONFIG["bindir"] || CONFIG['BINDIR']
21
+ $ruby_install_name = CONFIG['ruby_install_name'] || CONFIG['RUBY_INSTALL_NAME'] || 'ruby'
22
+ $ruby_ext = CONFIG['EXEEXT'] || ''
23
+ $ruby = File.join($bindir, ($ruby_install_name + $ruby_ext))
24
+
25
+ if !$site_libdir
26
+ $site_libdir = File.join($libdir, "site_ruby")
27
+ elsif $site_libdir !~ %r/#{Regexp.quote($version)}/
28
+ $site_libdir = File.join($site_libdir, $version)
29
+ end
30
+
31
+ def install_rb(srcdir=nil, destdir=nil, mode=nil, bin=nil)
32
+ #{{{
33
+ path = []
34
+ dir = []
35
+ Find.find(srcdir) do |f|
36
+ next unless FileTest.file?(f)
37
+ next if (f = f[srcdir.length+1..-1]) == nil
38
+ next if (/CVS$/ =~ File.dirname(f))
39
+ next if f =~ %r/\.lnk/
40
+ path.push f
41
+ dir |= [File.dirname(f)]
42
+ end
43
+ for f in dir
44
+ next if f == "."
45
+ next if f == "CVS"
46
+ File::makedirs(File.join(destdir, f))
47
+ end
48
+ for f in path
49
+ next if (/\~$/ =~ f)
50
+ next if (/^\./ =~ File.basename(f))
51
+ unless bin
52
+ File::install(File.join(srcdir, f), File.join(destdir, f), mode, true)
53
+ else
54
+ from = File.join(srcdir, f)
55
+ to = File.join(destdir, f)
56
+ shebangify(from) do |sf|
57
+ $deferr.print from, " -> ", File::catname(from, to), "\n"
58
+ $deferr.printf "chmod %04o %s\n", mode, to
59
+ File::install(sf, to, mode, false)
60
+ end
61
+ end
62
+ end
63
+ #}}}
64
+ end
65
+ def shebangify f
66
+ #{{{
67
+ open(f) do |fd|
68
+ buf = fd.read 42
69
+ if buf =~ %r/^\s*#\s*!.*ruby/o
70
+ ftmp = Tempfile::new("#{ $$ }_#{ File::basename(f) }")
71
+ begin
72
+ fd.rewind
73
+ ftmp.puts "#!#{ $ruby }"
74
+ while((buf = fd.read(8192)))
75
+ ftmp.write buf
76
+ end
77
+ ftmp.close
78
+ yield ftmp.path
79
+ ensure
80
+ ftmp.close!
81
+ end
82
+ else
83
+ yield f
84
+ end
85
+ end
86
+ #}}}
87
+ end
88
+ def ARGV.switch
89
+ #{{{
90
+ return nil if self.empty?
91
+ arg = self.shift
92
+ return nil if arg == '--'
93
+ if arg =~ /^-(.)(.*)/
94
+ return arg if $1 == '-'
95
+ raise 'unknown switch "-"' if $2.index('-')
96
+ self.unshift "-#{$2}" if $2.size > 0
97
+ "-#{$1}"
98
+ else
99
+ self.unshift arg
100
+ nil
101
+ end
102
+ #}}}
103
+ end
104
+ def ARGV.req_arg
105
+ #{{{
106
+ self.shift || raise('missing argument')
107
+ #}}}
108
+ end
109
+ def linkify d, linked = []
110
+ #--{{{
111
+ if test ?d, d
112
+ versioned = Dir[ File::join(d, "*-[0-9].[0-9].[0-9].rb") ]
113
+ versioned.each do |v|
114
+ src, dst = v, v.gsub(%r/\-[\d\.]+\.rb$/, '.rb')
115
+ lnk = nil
116
+ begin
117
+ if test ?l, dst
118
+ lnk = "#{ dst }.lnk"
119
+ puts "#{ dst } -> #{ lnk }"
120
+ File::rename dst, lnk
121
+ end
122
+ unless test ?e, dst
123
+ puts "#{ src } -> #{ dst }"
124
+ File::copy src, dst
125
+ linked << dst
126
+ end
127
+ ensure
128
+ if lnk
129
+ at_exit do
130
+ puts "#{ lnk } -> #{ dst }"
131
+ File::rename lnk, dst
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ linked
138
+ #--}}}
139
+ end
140
+
141
+
142
+ #
143
+ # main program
144
+ #
145
+
146
+ libdir = $site_libdir
147
+ bindir = $bindir
148
+ no_linkify = false
149
+ linked = nil
150
+ help = false
151
+
152
+ usage = <<-usage
153
+ #{ File::basename $0 }
154
+ -d, --destdir <destdir>
155
+ -l, --libdir <libdir>
156
+ -b, --bindir <bindir>
157
+ -r, --ruby <ruby>
158
+ -n, --no_linkify
159
+ -s, --sudo
160
+ -h, --help
161
+ usage
162
+
163
+ begin
164
+ while switch = ARGV.switch
165
+ case switch
166
+ when '-d', '--destdir'
167
+ libdir = ARGV.req_arg
168
+ when '-l', '--libdir'
169
+ libdir = ARGV.req_arg
170
+ when '-b', '--bindir'
171
+ bindir = ARGV.req_arg
172
+ when '-r', '--ruby'
173
+ $ruby = ARGV.req_arg
174
+ when '-n', '--no_linkify'
175
+ no_linkify = true
176
+ when '-s', '--sudo'
177
+ sudo = 'sudo'
178
+ when '-h', '--help'
179
+ help = true
180
+ else
181
+ raise "unknown switch #{switch.dump}"
182
+ end
183
+ end
184
+ rescue
185
+ STDERR.puts $!.to_s
186
+ STDERR.puts usage
187
+ exit 1
188
+ end
189
+
190
+ if help
191
+ STDOUT.puts usage
192
+ exit
193
+ end
194
+
195
+ unless no_linkify
196
+ linked = linkify('lib') + linkify('bin')
197
+ end
198
+
199
+ system "#{ $ruby } extconf.rb && make && #{ sudo } make install" if test(?s, 'extconf.rb')
200
+
201
+ install_rb(LIBDIR, libdir, LIBDIR_MODE)
202
+ install_rb(BINDIR, bindir, BINDIR_MODE, bin=true)
203
+
204
+ if linked
205
+ linked.each{|path| File::rm_f path}
206
+ end