dbmlite3 1.0.b1 → 2.0.0.pre.alpha.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +70 -19
- data/Rakefile +5 -4
- data/dbmlite3.gemspec +32 -10
- data/extras/benchmark.rb +172 -0
- data/lib/dbmlite3.rb +9 -949
- data/lib/internal_lite3/dbm.rb +542 -0
- data/lib/internal_lite3/error.rb +27 -0
- data/lib/internal_lite3/handle.rb +284 -0
- data/lib/internal_lite3/sql.rb +87 -0
- data/spec/dbmlite3_spec.rb +113 -72
- metadata +28 -27
- data/doc/Lite3/DBM.html +0 -2653
- data/doc/Lite3/Error.html +0 -135
- data/doc/Lite3/SQL.html +0 -390
- data/doc/Lite3.html +0 -117
- data/doc/_index.html +0 -152
- data/doc/class_list.html +0 -51
- data/doc/css/common.css +0 -1
- data/doc/css/full_list.css +0 -58
- data/doc/css/style.css +0 -496
- data/doc/file.README.html +0 -212
- data/doc/file_list.html +0 -56
- data/doc/frames.html +0 -17
- data/doc/index.html +0 -212
- data/doc/js/app.js +0 -314
- data/doc/js/full_list.js +0 -216
- data/doc/js/jquery.js +0 -4
- data/doc/method_list.html +0 -307
- data/doc/top-level-namespace.html +0 -110
data/doc/file.README.html
DELETED
@@ -1,212 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<meta charset="UTF-8">
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
-
<title>
|
7
|
-
File: README
|
8
|
-
|
9
|
-
— Documentation by YARD 0.9.25
|
10
|
-
|
11
|
-
</title>
|
12
|
-
|
13
|
-
<link rel="stylesheet" href="css/style.css" type="text/css" />
|
14
|
-
|
15
|
-
<link rel="stylesheet" href="css/common.css" type="text/css" />
|
16
|
-
|
17
|
-
<script type="text/javascript">
|
18
|
-
pathId = "README";
|
19
|
-
relpath = '';
|
20
|
-
</script>
|
21
|
-
|
22
|
-
|
23
|
-
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
24
|
-
|
25
|
-
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
26
|
-
|
27
|
-
|
28
|
-
</head>
|
29
|
-
<body>
|
30
|
-
<div class="nav_wrap">
|
31
|
-
<iframe id="nav" src="file_list.html?1"></iframe>
|
32
|
-
<div id="resizer"></div>
|
33
|
-
</div>
|
34
|
-
|
35
|
-
<div id="main" tabindex="-1">
|
36
|
-
<div id="header">
|
37
|
-
<div id="menu">
|
38
|
-
|
39
|
-
<a href="_index.html">Index</a> »
|
40
|
-
<span class="title">File: README</span>
|
41
|
-
|
42
|
-
</div>
|
43
|
-
|
44
|
-
<div id="search">
|
45
|
-
|
46
|
-
<a class="full_list_link" id="class_list_link"
|
47
|
-
href="class_list.html">
|
48
|
-
|
49
|
-
<svg width="24" height="24">
|
50
|
-
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
51
|
-
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
52
|
-
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
53
|
-
</svg>
|
54
|
-
</a>
|
55
|
-
|
56
|
-
</div>
|
57
|
-
<div class="clear"></div>
|
58
|
-
</div>
|
59
|
-
|
60
|
-
<div id="content"><div id='filecontents'><h1 id="simple-dbm-style-key-value-database-using-sqlite3">Simple DBM-style key-value database using SQLite3</h1>
|
61
|
-
|
62
|
-
<h2 id="description">Description</h2>
|
63
|
-
|
64
|
-
<p><code>dbmlite3</code> is a simple key-value store built on top of SQLite3 that
|
65
|
-
provides a Hash-like interface. It is a drop-in replacement for <code>DBM</code>
|
66
|
-
or <code>YAML::DBM</code> that uses SQLite3 to do the underlying storage.</p>
|
67
|
-
|
68
|
-
<h2 id="why">Why?</h2>
|
69
|
-
|
70
|
-
<p>Because DBM is really simple and SQLite3 is solid, reliable,
|
71
|
-
ubiquitous, and file-format-compatible across all platforms. This gem
|
72
|
-
gives you the best of both worlds.</p>
|
73
|
-
|
74
|
-
<h2 id="synopsis">Synopsis</h2>
|
75
|
-
|
76
|
-
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_require'>require</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>dbmlite3</span><span class='tstring_end'>'</span></span>
|
77
|
-
|
78
|
-
<span class='comment'># Open a table in a database
|
79
|
-
</span><span class='id identifier rubyid_settings'>settings</span> <span class='op'>=</span> <span class='const'><span class='object_link'><a href="Lite3.html" title="Lite3 (module)">Lite3</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Lite3/DBM.html" title="Lite3::DBM (class)">DBM</a></span></span><span class='period'>.</span><span class='id identifier rubyid_new'><span class='object_link'><a href="Lite3/DBM.html#initialize-instance_method" title="Lite3::DBM#initialize (method)">new</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>config.sqlite3</span><span class='tstring_end'>"</span></span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>settings</span><span class='tstring_end'>"</span></span><span class='rparen'>)</span>
|
80
|
-
|
81
|
-
<span class='comment'># You use it like a hash
|
82
|
-
</span><span class='id identifier rubyid_settings'>settings</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>speed</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='int'>88</span>
|
83
|
-
<span class='id identifier rubyid_settings'>settings</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>date</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='const'>Date</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='int'>1955</span><span class='comma'>,</span> <span class='int'>11</span><span class='comma'>,</span> <span class='int'>5</span><span class='rparen'>)</span> <span class='comment'># Normal Ruby values are allowed
|
84
|
-
</span><span class='id identifier rubyid_settings'>settings</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>power_threshold</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='float'>2.2</span>
|
85
|
-
|
86
|
-
<span class='id identifier rubyid_puts'>puts</span> <span class='id identifier rubyid_settings'>settings</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>power_threshold</span><span class='tstring_end'>'</span></span><span class='rbracket'>]</span>
|
87
|
-
|
88
|
-
<span class='id identifier rubyid_settings'>settings</span><span class='period'>.</span><span class='id identifier rubyid_each'>each</span><span class='lbrace'>{</span><span class='op'>|</span><span class='id identifier rubyid_k'>k</span><span class='comma'>,</span><span class='id identifier rubyid_v'>v</span><span class='op'>|</span> <span class='id identifier rubyid_puts'>puts</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>setting: </span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_k'>k</span><span class='embexpr_end'>}</span><span class='tstring_content'> = </span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_v'>v</span><span class='embexpr_end'>}</span><span class='tstring_end'>"</span></span> <span class='rbrace'>}</span>
|
89
|
-
|
90
|
-
<span class='comment'># But you also have transactions
|
91
|
-
</span><span class='id identifier rubyid_settings'>settings</span><span class='period'>.</span><span class='id identifier rubyid_transaction'>transaction</span><span class='lbrace'>{</span>
|
92
|
-
<span class='id identifier rubyid_settings'>settings</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>speed</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='id identifier rubyid_settings'>settings</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>speed</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>*</span> <span class='int'>2</span>
|
93
|
-
<span class='rbrace'>}</span>
|
94
|
-
|
95
|
-
<span class='comment'># You can open other tables in the same database if you want, as above
|
96
|
-
</span><span class='comment'># or with a block
|
97
|
-
</span><span class='const'><span class='object_link'><a href="Lite3.html" title="Lite3 (module)">Lite3</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Lite3/DBM.html" title="Lite3::DBM (class)">DBM</a></span></span><span class='period'>.</span><span class='id identifier rubyid_open'><span class='object_link'><a href="Lite3/DBM.html#open-class_method" title="Lite3::DBM.open (method)">open</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>config.sqlite3</span><span class='tstring_end'>"</span></span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>stats</span><span class='tstring_end'>"</span></span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_stats'>stats</span><span class='op'>|</span>
|
98
|
-
<span class='id identifier rubyid_stats'>stats</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>max</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='int'>42</span>
|
99
|
-
|
100
|
-
<span class='comment'># You can even open multiple handles to the same table if you need to
|
101
|
-
</span> <span class='const'><span class='object_link'><a href="Lite3.html" title="Lite3 (module)">Lite3</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Lite3/DBM.html" title="Lite3::DBM (class)">DBM</a></span></span><span class='period'>.</span><span class='id identifier rubyid_open'><span class='object_link'><a href="Lite3/DBM.html#open-class_method" title="Lite3::DBM.open (method)">open</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>config.sqlite3</span><span class='tstring_end'>"</span></span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>stats</span><span class='tstring_end'>"</span></span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_stats2'>stats2</span><span class='op'>|</span>
|
102
|
-
<span class='id identifier rubyid_stats2'>stats2</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>max</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>+=</span> <span class='int'>1</span>
|
103
|
-
<span class='rbrace'>}</span>
|
104
|
-
|
105
|
-
<span class='id identifier rubyid_puts'>puts</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>stats=</span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_stats'>stats</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>max</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span><span class='embexpr_end'>}</span><span class='tstring_end'>"</span></span>
|
106
|
-
<span class='rbrace'>}</span>
|
107
|
-
|
108
|
-
<span class='id identifier rubyid_settings'>settings</span><span class='period'>.</span><span class='id identifier rubyid_close'>close</span>
|
109
|
-
</code></pre>
|
110
|
-
|
111
|
-
<p>Complete documentation is available in the accompanying rdoc.</p>
|
112
|
-
|
113
|
-
<h2 id="installation">Installation</h2>
|
114
|
-
|
115
|
-
<p><code>dbmlite3</code> is available as a gem:</p>
|
116
|
-
|
117
|
-
<pre class="code ruby"><code class="ruby">$ [sudo] gem install dbmlite3
|
118
|
-
</code></pre>
|
119
|
-
|
120
|
-
<p>Alternately, you can fetch the source code from GitLab and build it yourself:</p>
|
121
|
-
|
122
|
-
<pre class="code ruby"><code class="ruby">$ git clone https://gitlab.com/suetanvil/dbmlite3
|
123
|
-
$ cd dbmlite3
|
124
|
-
$ rake
|
125
|
-
</code></pre>
|
126
|
-
|
127
|
-
<p>Obviously, it depends on the gem <code>sqlite3</code>.</p>
|
128
|
-
|
129
|
-
<h2 id="quirks-and-hints">Quirks and Hints</h2>
|
130
|
-
|
131
|
-
<h3 id="remember-that-a-dbm-is-a-potentially-shared-file">Remember that a <code>DBM</code> is a (potentially) shared file</h3>
|
132
|
-
|
133
|
-
<p>It is important to keep in mind that while <code>Lite3::DBM</code> objects
|
134
|
-
look like Hashes, they are accessing files on disk that other
|
135
|
-
processes could modify at any time.</p>
|
136
|
-
|
137
|
-
<p>For example, an innocuous-looking expression like </p>
|
138
|
-
|
139
|
-
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_db'>db</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>foo</span><span class='tstring_end'>'</span></span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='id identifier rubyid_db'>db</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>foo</span><span class='tstring_end'>'</span></span><span class='rbracket'>]</span> <span class='op'>+</span> <span class='int'>1</span>
|
140
|
-
</code></pre>
|
141
|
-
|
142
|
-
<p>or its shorter equivalent</p>
|
143
|
-
|
144
|
-
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_db'>db</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>foo</span><span class='tstring_end'>'</span></span><span class='rbracket'>]</span> <span class='op'>+=</span> <span class='int'>1</span>
|
145
|
-
</code></pre>
|
146
|
-
|
147
|
-
<p>contains a race condition. If (e.g.) two copies of this script are
|
148
|
-
running at the same time, it is possible for both to perform the read
|
149
|
-
before one of them writes, losing the others' result.</p>
|
150
|
-
|
151
|
-
<p>There are two ways to deal with this. You can wrap the
|
152
|
-
read-modify-write cycle in a transaction:</p>
|
153
|
-
|
154
|
-
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_db'>db</span><span class='period'>.</span><span class='id identifier rubyid_transaction'>transaction</span> <span class='lbrace'>{</span> <span class='id identifier rubyid_db'>db</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>foo</span><span class='tstring_end'>'</span></span><span class='rbracket'>]</span> <span class='op'>+=</span> <span class='int'>1</span> <span class='rbrace'>}</span>
|
155
|
-
</code></pre>
|
156
|
-
|
157
|
-
<p>Or, of course, you could just design your script or program so that
|
158
|
-
only one program accesses the table at a time.</p>
|
159
|
-
|
160
|
-
<h3 id="transactions-and-performance">Transactions and performance</h3>
|
161
|
-
|
162
|
-
<p>If you need to do a large number of accesses in a short amount of
|
163
|
-
time (e.g. loading data from a file), it is significantly faster to
|
164
|
-
do these in batches in one or more transactions.</p>
|
165
|
-
|
166
|
-
<h3 id="serialization-safety">Serialization Safety</h3>
|
167
|
-
|
168
|
-
<p><code>Lite3::DBM</code> stores Ruby data by first serializing values using the
|
169
|
-
<code>Marshal</code> or <code>Psych</code> modules. This can pose a security risk if an
|
170
|
-
untrusted third party has direct access to the underlying SQLite3
|
171
|
-
database. This tends to be pretty rare for most use-cases but if it
|
172
|
-
is a concern, you can always configure <code>Lite3::DBM</code> to store its
|
173
|
-
values as plain strings.</p>
|
174
|
-
|
175
|
-
<h3 id="forking-safely">Forking safely</h3>
|
176
|
-
|
177
|
-
<p>It is a documented limitation of SQLite3 that database objects
|
178
|
-
cannot be carried across a process fork. Either the parent or the
|
179
|
-
child process will keep the open handle and the other one must
|
180
|
-
forget it completely.</p>
|
181
|
-
|
182
|
-
<p>For this reason, if you need both the parent and child process to
|
183
|
-
be able to use <code>Lite3::DBM</code> after a <code>fork</code>, you must first call
|
184
|
-
<code>Lite3::SQL.close_all</code>. Not only will this make it safe but it
|
185
|
-
also lets the child and parent use the same <code>Lite3::DBM</code> objects.</p>
|
186
|
-
|
187
|
-
<h3 id="lite3-dbm-objects-act-like-file-handles-but-are-not"><code>Lite3::DBM</code> objects act like file handles but are not</h3>
|
188
|
-
|
189
|
-
<p>While it is generally safe to treat <code>Lite3::DBM</code> as a wrapper
|
190
|
-
around file handle (i.e. <code>open</code> and <code>close</code> work as expected), you
|
191
|
-
should be aware that this is not precisely the way things
|
192
|
-
actually work. Instead, the gem maintains a pool of database
|
193
|
-
handles, one per file, and associates them with <code>Lite3::DBM</code>
|
194
|
-
instances as needed. This is necessary for transactions to work
|
195
|
-
correctly.</p>
|
196
|
-
|
197
|
-
<p>See the reference doc for <code>Lite3::SQL</code> for more details.</p>
|
198
|
-
|
199
|
-
<p>Mostly, you don't need to worry about this but certain types of
|
200
|
-
bugs could behave in unexpected ways and knowing this may help you
|
201
|
-
make sense of them.</p>
|
202
|
-
</div></div>
|
203
|
-
|
204
|
-
<div id="footer">
|
205
|
-
Generated on Sun Feb 27 17:39:45 2022 by
|
206
|
-
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
207
|
-
0.9.25 (ruby-2.7.0).
|
208
|
-
</div>
|
209
|
-
|
210
|
-
</div>
|
211
|
-
</body>
|
212
|
-
</html>
|
data/doc/file_list.html
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
5
|
-
<meta charset="utf-8" />
|
6
|
-
|
7
|
-
<link rel="stylesheet" href="css/full_list.css" type="text/css" media="screen" />
|
8
|
-
|
9
|
-
<link rel="stylesheet" href="css/common.css" type="text/css" media="screen" />
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
14
|
-
|
15
|
-
<script type="text/javascript" charset="utf-8" src="js/full_list.js"></script>
|
16
|
-
|
17
|
-
|
18
|
-
<title>File List</title>
|
19
|
-
<base id="base_target" target="_parent" />
|
20
|
-
</head>
|
21
|
-
<body>
|
22
|
-
<div id="content">
|
23
|
-
<div class="fixed_header">
|
24
|
-
<h1 id="full_list_header">File List</h1>
|
25
|
-
<div id="full_list_nav">
|
26
|
-
|
27
|
-
<span><a target="_self" href="class_list.html">
|
28
|
-
Classes
|
29
|
-
</a></span>
|
30
|
-
|
31
|
-
<span><a target="_self" href="method_list.html">
|
32
|
-
Methods
|
33
|
-
</a></span>
|
34
|
-
|
35
|
-
<span><a target="_self" href="file_list.html">
|
36
|
-
Files
|
37
|
-
</a></span>
|
38
|
-
|
39
|
-
</div>
|
40
|
-
|
41
|
-
<div id="search">Search: <input type="text" /></div>
|
42
|
-
</div>
|
43
|
-
|
44
|
-
<ul id="full_list" class="file">
|
45
|
-
|
46
|
-
|
47
|
-
<li id="object_README" class="odd">
|
48
|
-
<div class="item"><span class="object_link"><a href="index.html" title="README">README</a></span></div>
|
49
|
-
</li>
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
</ul>
|
54
|
-
</div>
|
55
|
-
</body>
|
56
|
-
</html>
|
data/doc/frames.html
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<meta charset="utf-8">
|
5
|
-
<title>Documentation by YARD 0.9.25</title>
|
6
|
-
</head>
|
7
|
-
<script type="text/javascript">
|
8
|
-
var match = unescape(window.location.hash).match(/^#!(.+)/);
|
9
|
-
var name = match ? match[1] : 'index.html';
|
10
|
-
name = name.replace(/^(\w+):\/\//, '').replace(/^\/\//, '');
|
11
|
-
window.top.location = name;
|
12
|
-
</script>
|
13
|
-
<noscript>
|
14
|
-
<h1>Oops!</h1>
|
15
|
-
<h2>YARD requires JavaScript!</h2>
|
16
|
-
</noscript>
|
17
|
-
</html>
|
data/doc/index.html
DELETED
@@ -1,212 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<meta charset="UTF-8">
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
-
<title>
|
7
|
-
File: README
|
8
|
-
|
9
|
-
— Documentation by YARD 0.9.25
|
10
|
-
|
11
|
-
</title>
|
12
|
-
|
13
|
-
<link rel="stylesheet" href="css/style.css" type="text/css" />
|
14
|
-
|
15
|
-
<link rel="stylesheet" href="css/common.css" type="text/css" />
|
16
|
-
|
17
|
-
<script type="text/javascript">
|
18
|
-
pathId = "README";
|
19
|
-
relpath = '';
|
20
|
-
</script>
|
21
|
-
|
22
|
-
|
23
|
-
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
24
|
-
|
25
|
-
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
26
|
-
|
27
|
-
|
28
|
-
</head>
|
29
|
-
<body>
|
30
|
-
<div class="nav_wrap">
|
31
|
-
<iframe id="nav" src="class_list.html?1"></iframe>
|
32
|
-
<div id="resizer"></div>
|
33
|
-
</div>
|
34
|
-
|
35
|
-
<div id="main" tabindex="-1">
|
36
|
-
<div id="header">
|
37
|
-
<div id="menu">
|
38
|
-
|
39
|
-
<a href="_index.html">Index</a> »
|
40
|
-
<span class="title">File: README</span>
|
41
|
-
|
42
|
-
</div>
|
43
|
-
|
44
|
-
<div id="search">
|
45
|
-
|
46
|
-
<a class="full_list_link" id="class_list_link"
|
47
|
-
href="class_list.html">
|
48
|
-
|
49
|
-
<svg width="24" height="24">
|
50
|
-
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
51
|
-
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
52
|
-
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
53
|
-
</svg>
|
54
|
-
</a>
|
55
|
-
|
56
|
-
</div>
|
57
|
-
<div class="clear"></div>
|
58
|
-
</div>
|
59
|
-
|
60
|
-
<div id="content"><div id='filecontents'><h1 id="simple-dbm-style-key-value-database-using-sqlite3">Simple DBM-style key-value database using SQLite3</h1>
|
61
|
-
|
62
|
-
<h2 id="description">Description</h2>
|
63
|
-
|
64
|
-
<p><code>dbmlite3</code> is a simple key-value store built on top of SQLite3 that
|
65
|
-
provides a Hash-like interface. It is a drop-in replacement for <code>DBM</code>
|
66
|
-
or <code>YAML::DBM</code> that uses SQLite3 to do the underlying storage.</p>
|
67
|
-
|
68
|
-
<h2 id="why">Why?</h2>
|
69
|
-
|
70
|
-
<p>Because DBM is really simple and SQLite3 is solid, reliable,
|
71
|
-
ubiquitous, and file-format-compatible across all platforms. This gem
|
72
|
-
gives you the best of both worlds.</p>
|
73
|
-
|
74
|
-
<h2 id="synopsis">Synopsis</h2>
|
75
|
-
|
76
|
-
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_require'>require</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>dbmlite3</span><span class='tstring_end'>'</span></span>
|
77
|
-
|
78
|
-
<span class='comment'># Open a table in a database
|
79
|
-
</span><span class='id identifier rubyid_settings'>settings</span> <span class='op'>=</span> <span class='const'><span class='object_link'><a href="Lite3.html" title="Lite3 (module)">Lite3</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Lite3/DBM.html" title="Lite3::DBM (class)">DBM</a></span></span><span class='period'>.</span><span class='id identifier rubyid_new'><span class='object_link'><a href="Lite3/DBM.html#initialize-instance_method" title="Lite3::DBM#initialize (method)">new</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>config.sqlite3</span><span class='tstring_end'>"</span></span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>settings</span><span class='tstring_end'>"</span></span><span class='rparen'>)</span>
|
80
|
-
|
81
|
-
<span class='comment'># You use it like a hash
|
82
|
-
</span><span class='id identifier rubyid_settings'>settings</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>speed</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='int'>88</span>
|
83
|
-
<span class='id identifier rubyid_settings'>settings</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>date</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='const'>Date</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='int'>1955</span><span class='comma'>,</span> <span class='int'>11</span><span class='comma'>,</span> <span class='int'>5</span><span class='rparen'>)</span> <span class='comment'># Normal Ruby values are allowed
|
84
|
-
</span><span class='id identifier rubyid_settings'>settings</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>power_threshold</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='float'>2.2</span>
|
85
|
-
|
86
|
-
<span class='id identifier rubyid_puts'>puts</span> <span class='id identifier rubyid_settings'>settings</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>power_threshold</span><span class='tstring_end'>'</span></span><span class='rbracket'>]</span>
|
87
|
-
|
88
|
-
<span class='id identifier rubyid_settings'>settings</span><span class='period'>.</span><span class='id identifier rubyid_each'>each</span><span class='lbrace'>{</span><span class='op'>|</span><span class='id identifier rubyid_k'>k</span><span class='comma'>,</span><span class='id identifier rubyid_v'>v</span><span class='op'>|</span> <span class='id identifier rubyid_puts'>puts</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>setting: </span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_k'>k</span><span class='embexpr_end'>}</span><span class='tstring_content'> = </span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_v'>v</span><span class='embexpr_end'>}</span><span class='tstring_end'>"</span></span> <span class='rbrace'>}</span>
|
89
|
-
|
90
|
-
<span class='comment'># But you also have transactions
|
91
|
-
</span><span class='id identifier rubyid_settings'>settings</span><span class='period'>.</span><span class='id identifier rubyid_transaction'>transaction</span><span class='lbrace'>{</span>
|
92
|
-
<span class='id identifier rubyid_settings'>settings</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>speed</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='id identifier rubyid_settings'>settings</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>speed</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>*</span> <span class='int'>2</span>
|
93
|
-
<span class='rbrace'>}</span>
|
94
|
-
|
95
|
-
<span class='comment'># You can open other tables in the same database if you want, as above
|
96
|
-
</span><span class='comment'># or with a block
|
97
|
-
</span><span class='const'><span class='object_link'><a href="Lite3.html" title="Lite3 (module)">Lite3</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Lite3/DBM.html" title="Lite3::DBM (class)">DBM</a></span></span><span class='period'>.</span><span class='id identifier rubyid_open'><span class='object_link'><a href="Lite3/DBM.html#open-class_method" title="Lite3::DBM.open (method)">open</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>config.sqlite3</span><span class='tstring_end'>"</span></span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>stats</span><span class='tstring_end'>"</span></span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_stats'>stats</span><span class='op'>|</span>
|
98
|
-
<span class='id identifier rubyid_stats'>stats</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>max</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='int'>42</span>
|
99
|
-
|
100
|
-
<span class='comment'># You can even open multiple handles to the same table if you need to
|
101
|
-
</span> <span class='const'><span class='object_link'><a href="Lite3.html" title="Lite3 (module)">Lite3</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Lite3/DBM.html" title="Lite3::DBM (class)">DBM</a></span></span><span class='period'>.</span><span class='id identifier rubyid_open'><span class='object_link'><a href="Lite3/DBM.html#open-class_method" title="Lite3::DBM.open (method)">open</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>config.sqlite3</span><span class='tstring_end'>"</span></span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>stats</span><span class='tstring_end'>"</span></span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_stats2'>stats2</span><span class='op'>|</span>
|
102
|
-
<span class='id identifier rubyid_stats2'>stats2</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>max</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>+=</span> <span class='int'>1</span>
|
103
|
-
<span class='rbrace'>}</span>
|
104
|
-
|
105
|
-
<span class='id identifier rubyid_puts'>puts</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>stats=</span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_stats'>stats</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>max</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span><span class='embexpr_end'>}</span><span class='tstring_end'>"</span></span>
|
106
|
-
<span class='rbrace'>}</span>
|
107
|
-
|
108
|
-
<span class='id identifier rubyid_settings'>settings</span><span class='period'>.</span><span class='id identifier rubyid_close'>close</span>
|
109
|
-
</code></pre>
|
110
|
-
|
111
|
-
<p>Complete documentation is available in the accompanying rdoc.</p>
|
112
|
-
|
113
|
-
<h2 id="installation">Installation</h2>
|
114
|
-
|
115
|
-
<p><code>dbmlite3</code> is available as a gem:</p>
|
116
|
-
|
117
|
-
<pre class="code ruby"><code class="ruby">$ [sudo] gem install dbmlite3
|
118
|
-
</code></pre>
|
119
|
-
|
120
|
-
<p>Alternately, you can fetch the source code from GitLab and build it yourself:</p>
|
121
|
-
|
122
|
-
<pre class="code ruby"><code class="ruby">$ git clone https://gitlab.com/suetanvil/dbmlite3
|
123
|
-
$ cd dbmlite3
|
124
|
-
$ rake
|
125
|
-
</code></pre>
|
126
|
-
|
127
|
-
<p>Obviously, it depends on the gem <code>sqlite3</code>.</p>
|
128
|
-
|
129
|
-
<h2 id="quirks-and-hints">Quirks and Hints</h2>
|
130
|
-
|
131
|
-
<h3 id="remember-that-a-dbm-is-a-potentially-shared-file">Remember that a <code>DBM</code> is a (potentially) shared file</h3>
|
132
|
-
|
133
|
-
<p>It is important to keep in mind that while <code>Lite3::DBM</code> objects
|
134
|
-
look like Hashes, they are accessing files on disk that other
|
135
|
-
processes could modify at any time.</p>
|
136
|
-
|
137
|
-
<p>For example, an innocuous-looking expression like </p>
|
138
|
-
|
139
|
-
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_db'>db</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>foo</span><span class='tstring_end'>'</span></span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='id identifier rubyid_db'>db</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>foo</span><span class='tstring_end'>'</span></span><span class='rbracket'>]</span> <span class='op'>+</span> <span class='int'>1</span>
|
140
|
-
</code></pre>
|
141
|
-
|
142
|
-
<p>or its shorter equivalent</p>
|
143
|
-
|
144
|
-
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_db'>db</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>foo</span><span class='tstring_end'>'</span></span><span class='rbracket'>]</span> <span class='op'>+=</span> <span class='int'>1</span>
|
145
|
-
</code></pre>
|
146
|
-
|
147
|
-
<p>contains a race condition. If (e.g.) two copies of this script are
|
148
|
-
running at the same time, it is possible for both to perform the read
|
149
|
-
before one of them writes, losing the others' result.</p>
|
150
|
-
|
151
|
-
<p>There are two ways to deal with this. You can wrap the
|
152
|
-
read-modify-write cycle in a transaction:</p>
|
153
|
-
|
154
|
-
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_db'>db</span><span class='period'>.</span><span class='id identifier rubyid_transaction'>transaction</span> <span class='lbrace'>{</span> <span class='id identifier rubyid_db'>db</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>foo</span><span class='tstring_end'>'</span></span><span class='rbracket'>]</span> <span class='op'>+=</span> <span class='int'>1</span> <span class='rbrace'>}</span>
|
155
|
-
</code></pre>
|
156
|
-
|
157
|
-
<p>Or, of course, you could just design your script or program so that
|
158
|
-
only one program accesses the table at a time.</p>
|
159
|
-
|
160
|
-
<h3 id="transactions-and-performance">Transactions and performance</h3>
|
161
|
-
|
162
|
-
<p>If you need to do a large number of accesses in a short amount of
|
163
|
-
time (e.g. loading data from a file), it is significantly faster to
|
164
|
-
do these in batches in one or more transactions.</p>
|
165
|
-
|
166
|
-
<h3 id="serialization-safety">Serialization Safety</h3>
|
167
|
-
|
168
|
-
<p><code>Lite3::DBM</code> stores Ruby data by first serializing values using the
|
169
|
-
<code>Marshal</code> or <code>Psych</code> modules. This can pose a security risk if an
|
170
|
-
untrusted third party has direct access to the underlying SQLite3
|
171
|
-
database. This tends to be pretty rare for most use-cases but if it
|
172
|
-
is a concern, you can always configure <code>Lite3::DBM</code> to store its
|
173
|
-
values as plain strings.</p>
|
174
|
-
|
175
|
-
<h3 id="forking-safely">Forking safely</h3>
|
176
|
-
|
177
|
-
<p>It is a documented limitation of SQLite3 that database objects
|
178
|
-
cannot be carried across a process fork. Either the parent or the
|
179
|
-
child process will keep the open handle and the other one must
|
180
|
-
forget it completely.</p>
|
181
|
-
|
182
|
-
<p>For this reason, if you need both the parent and child process to
|
183
|
-
be able to use <code>Lite3::DBM</code> after a <code>fork</code>, you must first call
|
184
|
-
<code>Lite3::SQL.close_all</code>. Not only will this make it safe but it
|
185
|
-
also lets the child and parent use the same <code>Lite3::DBM</code> objects.</p>
|
186
|
-
|
187
|
-
<h3 id="lite3-dbm-objects-act-like-file-handles-but-are-not"><code>Lite3::DBM</code> objects act like file handles but are not</h3>
|
188
|
-
|
189
|
-
<p>While it is generally safe to treat <code>Lite3::DBM</code> as a wrapper
|
190
|
-
around file handle (i.e. <code>open</code> and <code>close</code> work as expected), you
|
191
|
-
should be aware that this is not precisely the way things
|
192
|
-
actually work. Instead, the gem maintains a pool of database
|
193
|
-
handles, one per file, and associates them with <code>Lite3::DBM</code>
|
194
|
-
instances as needed. This is necessary for transactions to work
|
195
|
-
correctly.</p>
|
196
|
-
|
197
|
-
<p>See the reference doc for <code>Lite3::SQL</code> for more details.</p>
|
198
|
-
|
199
|
-
<p>Mostly, you don't need to worry about this but certain types of
|
200
|
-
bugs could behave in unexpected ways and knowing this may help you
|
201
|
-
make sense of them.</p>
|
202
|
-
</div></div>
|
203
|
-
|
204
|
-
<div id="footer">
|
205
|
-
Generated on Sun Feb 27 17:39:45 2022 by
|
206
|
-
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
207
|
-
0.9.25 (ruby-2.7.0).
|
208
|
-
</div>
|
209
|
-
|
210
|
-
</div>
|
211
|
-
</body>
|
212
|
-
</html>
|