sldb 0.1.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/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