ruby-qdbm 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/curia.rb ADDED
@@ -0,0 +1,598 @@
1
+ #=================================================================================================
2
+ # Ruby API of Curia, the basic API of QDBM
3
+ # Copyright (C) 2000-2006 Mikio Hirabayashi
4
+ # This file is part of QDBM, Quick Database Manager.
5
+ # QDBM is free software; you can redistribute it and/or modify it under the terms of the GNU
6
+ # Lesser General Public License as published by the Free Software Foundation; either version
7
+ # 2.1 of the License or any later version. QDBM is distributed in the hope that it will be
8
+ # useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
10
+ # details.
11
+ # You should have received a copy of the GNU Lesser General Public License along with QDBM; if
12
+ # not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
13
+ # 02111-1307 USA.
14
+ #=================================================================================================
15
+
16
+
17
+ require 'mod_curia'
18
+ require 'thread'
19
+
20
+
21
+
22
+ ##
23
+ # require 'curia'
24
+ # The library `curia' should be included in application codes.
25
+ # An instance of the class `Curia' is used as a database handle.
26
+ # `Curia' performs Mix-in of `Enumerable'.
27
+ # Each method of `Curia' throws an exception of `Curia::EANY' or its sub classes when an error
28
+ # occurs: `Curia::ENOERR', `Curia::EFATAL', `Curia::EMODE', `Curia::EBROKEN', `Curia::EKEEP',
29
+ # `Curia::ENOITEM', `Curia::EALLOC', `Curia::EMAP', `Curia::EOPEN', `Curia::ECLOSE',
30
+ # `Curia::ETRUNC', `Curia::ESYNC', `Curia::ESTAT', `Curia::ESEEK', `Curia::EREAD',
31
+ # `Curia::EWRITE', `Curia::ELOCK', `Curia::EUNLINK', `Curia::EMKDIR', `Curia::ERMDIR' and
32
+ # `Curia::EMISC'.
33
+ #
34
+ class Curia
35
+ include Mod_Curia, Enumerable
36
+ #----------------------------------------------------------------
37
+ # class constants
38
+ #----------------------------------------------------------------
39
+ MyMutex = Mutex::new()
40
+ #----------------------------------------------------------------
41
+ # class methods
42
+ #----------------------------------------------------------------
43
+ public
44
+ ##
45
+ # curia = Curia::new(name, omode, bnum, dnum)
46
+ # Constructor: Get a database handle.
47
+ # `name' specifies the name of a database directory.
48
+ # `omode' specifies the connection mode: `Curia::OWRITER' as a writer, `Curia::OREADER' as a
49
+ # reader. If the mode is `Curia::OWRITER', the following may be added by bitwise or:
50
+ # `Curia::OCREAT', which means it creates a new database if not exist, `Curia::OTRUNC', which
51
+ # means it creates a new database regardless if one exists. Both of `Curia::OREADER' and
52
+ # `Curia::OWRITER' can be added to by bitwise or: `Curia::ONOLCK', which means it opens a
53
+ # database directory without file locking, or `Curia::OLCKNB', which means locking is
54
+ # performed without blocking. `Curia::OCREAT' can be added to by bitwise or: `Curia::OSPARSE',
55
+ # which means it creates database files as sparse files. If it is omitted, `Curia::OREADER'
56
+ # is specified.
57
+ # `bnum' specifies the number of elements of the bucket array. If it is omitted or not more
58
+ # than 0, the default value is specified. The size of a bucket array is determined on
59
+ # creating, and can not be changed except for by optimization of the database. Suggested
60
+ # size of a bucket array is about from 0.5 to 4 times of the number of all records to store.
61
+ # `dnum' specifies the number of division of the database. If it is omitted or not more than
62
+ # 0, the default value is specified. The number of division can not be changed from the
63
+ # initial value. The max number of division is 512.
64
+ # The return value is the database handle.
65
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
66
+ # If a block parameter is given, this method works as an iterator. A database handle is
67
+ # opened and passed via the first argument of the block. The database handle is surely
68
+ # closed when the block is over.
69
+ # While connecting as a writer, an exclusive lock is invoked to the database directory.
70
+ # While connecting as a reader, a shared lock is invoked to the database directory. The thread
71
+ # blocks until the lock is achieved. If `Curia::ONOLCK' is used, the application is
72
+ # responsible for exclusion control.
73
+ #
74
+ #@ DEFINED IMPLICITLY
75
+ ##
76
+ # curia = Curia::open(name, omode, bnum, dnum)
77
+ # Constructor: An alias of `new'.
78
+ #
79
+ #@ DEFINED OUTSIDE
80
+ #----------------------------------------------------------------
81
+ # private methods
82
+ #----------------------------------------------------------------
83
+ private
84
+ #=
85
+ # initialize(name, omode, bnum)
86
+ # Method: Called implicitly by the constructor.
87
+ #
88
+ def initialize(name, omode = OREADER, bnum = -1, dnum = -1)
89
+ @silent = false
90
+ MyMutex.synchronize() do
91
+ @index = mod_open(name, omode, bnum, dnum)
92
+ @name = name
93
+ end
94
+ if(iterator?)
95
+ begin
96
+ yield(self)
97
+ ensure
98
+ close()
99
+ end
100
+ end
101
+ self
102
+ end
103
+ #=
104
+ # clone()
105
+ # Method: Forbidden to use.
106
+ #
107
+ def clone
108
+ raise(CuriaError)
109
+ end
110
+ #=
111
+ # dup()
112
+ # Method: Forbidden to use.
113
+ #
114
+ alias dup clone
115
+ #----------------------------------------------------------------
116
+ # public methods
117
+ #----------------------------------------------------------------
118
+ public
119
+ ##
120
+ # bool = curia.close()
121
+ # Method: Close the database handle.
122
+ # The return value is always true.
123
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
124
+ # Because the region of a closed handle is released, it becomes impossible to use the handle.
125
+ # Updating a database is assured to be written when the handle is closed. If a writer opens
126
+ # a database but does not close it appropriately, the database will be broken.
127
+ #
128
+ def close()
129
+ MyMutex.synchronize() do
130
+ begin
131
+ mod_close(@index)
132
+ ensure
133
+ @index = -1
134
+ end
135
+ end
136
+ end
137
+ ##
138
+ # curia.silent = bool
139
+ # Method: Set the flag whether to repress frequent exceptions.
140
+ # The return value is the assigned value.
141
+ #
142
+ def silent=(value)
143
+ @silent = value ? true : false
144
+ mod_setsilent(@index, silent ? 1 : 0)
145
+ @silent
146
+ end
147
+ def silent
148
+ @silent
149
+ end
150
+ ##
151
+ # bool = curia.put(key, val, dmode)
152
+ # Method: Store a record.
153
+ # `key' specifies a key. Although it must be an instance of String, binary data is okey.
154
+ # `val' specifies a value. Although it must be an instance of String, binary data is okey.
155
+ # `dmode' specifies behavior when the key overlaps, by the following values: `Curia::DOVER',
156
+ # which means the specified value overwrites the existing one, `Curia::DKEEP', which means
157
+ # the existing value is kept, `Curia::DCAT', which means the specified value is concatenated
158
+ # at the end of the existing value. If it is omitted, `Curia::DOVER' is specified.
159
+ # The return value is always true. However, if the silent flag is true and replace is
160
+ # cancelled, false is returned instead of exception.
161
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs or replace
162
+ # is cancelled.
163
+ #
164
+ def put(key, val, dmode = DOVER)
165
+ mod_put(@index, key, val, dmode)
166
+ end
167
+ ##
168
+ # bool = curia.store(key, val)
169
+ # Method: An alias of `put'.
170
+ #
171
+ alias store put
172
+ ##
173
+ # curia[key] = val
174
+ # Method: An alias of `put'.
175
+ #
176
+ alias []= put
177
+ ##
178
+ # bool = curia.out(key)
179
+ # Method: Delete a record.
180
+ # `key' specifies a key. Although it must be an instance of String, binary data is okey.
181
+ # The return value is always true. However, if the silent flag is true and no record
182
+ # corresponds, false is returned instead of exception.
183
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs or no record
184
+ # corresponds.
185
+ #
186
+ def out(key)
187
+ mod_out(@index, key)
188
+ end
189
+ ##
190
+ # bool = curia.delete(key)
191
+ # Method: An alias of `out'.
192
+ #
193
+ alias delete out
194
+ ##
195
+ # bool = curia.clear()
196
+ # Method: Delete all records.
197
+ # The return value is always true.
198
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
199
+ #
200
+ def clear
201
+ MyMutex.synchronize() do
202
+ iterinit()
203
+ while(rnum() > 0)
204
+ out(iternext())
205
+ end
206
+ end
207
+ true
208
+ end
209
+ ##
210
+ # str = curia.get(key, start, max)
211
+ # Method: Retrieve a record.
212
+ # `key' specifies a key. Although it must be an instance of String, binary data is okey.
213
+ # `start' specifies the offset address of the beginning of the region of the value to be read.
214
+ # If it is negative or omitted, the offset is specified as 0.
215
+ # `max' specifies the max size to be read. If it is negative or omitted, the size to read is
216
+ # unlimited.
217
+ # The return value is an instance of the value of the corresponding record. If the silent flag
218
+ # is true and no record corresponds, nil is returned instead of exception.
219
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs, no record
220
+ # corresponds, or the size of the value of the corresponding record is less than `max'.
221
+ #
222
+ def get(key, start = 0, max = -1)
223
+ mod_get(@index, key, start, max)
224
+ end
225
+ ##
226
+ # str = curia.fetch(key, defval)
227
+ # Method: Retrieve a record.
228
+ # `key' specifies a key. Although it must be an instance of String, binary data is okey.
229
+ # `defval' specifies the default value used when no record corresponds. If it is omitted, nil
230
+ # is specified.
231
+ # The return value is an instance of the value of the corresponding record, or the default
232
+ # value if no record corresponds.
233
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
234
+ #
235
+ def fetch(key, defval = nil)
236
+ if @silent
237
+ if val = mod_get(@index, key, 0, -1)
238
+ val
239
+ else
240
+ defval
241
+ end
242
+ else
243
+ begin
244
+ mod_get(@index, key, 0, -1)
245
+ rescue ENOITEM
246
+ defval
247
+ end
248
+ end
249
+ end
250
+ ##
251
+ # str = curia[key]
252
+ # Method: An alias of `fetch'.
253
+ #
254
+ alias [] fetch
255
+ ##
256
+ # num = curia.vsiz(key)
257
+ # Method: Get the size of the value of a record.
258
+ # `key' specifies a key. Although it must be an instance of String, binary data is okey.
259
+ # The return value is the size of the value of the corresponding record. If the silent flag
260
+ # is true and no record corresponds, -1 is returned instead of exception.
261
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs or no record
262
+ # corresponds.
263
+ # Because this method does not read the entity of a record, it is faster than `get'.
264
+ #
265
+ def vsiz(key)
266
+ mod_vsiz(@index, key)
267
+ end
268
+ ##
269
+ # bool = curia.iterinit()
270
+ # Method: Initialize the iterator of the database handle.
271
+ # The return value is always true.
272
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
273
+ # The iterator is used in order to access the key of every record stored in a database.
274
+ #
275
+ def iterinit()
276
+ mod_iterinit(@index)
277
+ end
278
+ ##
279
+ # str = curia.iternext()
280
+ # Method: Get the next key of the iterator.
281
+ # The return value is the value of the next key. If the silent flag is true and no record
282
+ # corresponds, nil is returned instead of exception.
283
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs or no record
284
+ # is to be get out of the iterator.
285
+ # It is possible to access every record by iteration of calling this method. However, it is
286
+ # not assured if updating the database is occurred while the iteration. Besides, the order
287
+ # of this traversal access method is arbitrary, so it is not assured that the order of
288
+ # storing matches the one of the traversal access.
289
+ #
290
+ def iternext()
291
+ mod_iternext(@index)
292
+ end
293
+ ##
294
+ # bool = curia.setalign(align)
295
+ # Method: Set alignment of the database handle.
296
+ # `align' specifies the basic size of alignment. If it is omitted, alignment is cleared.
297
+ # The return value is always true.
298
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
299
+ # If alignment is set to a database, the efficiency of overwriting values is improved.
300
+ # The size of alignment is suggested to be average size of the values of the records to be
301
+ # stored. If alignment is positive, padding whose size is multiple number of the alignment
302
+ # is placed. If alignment is negative, as `vsiz' is the size of a value, the size of padding
303
+ # is calculated with `(vsiz / pow(2, abs(align) - 1))'. Because alignment setting is not
304
+ # saved in a database, you should specify alignment every opening a database.
305
+ #
306
+ def setalign(align = 0)
307
+ mod_setalign(@index, align)
308
+ end
309
+ ##
310
+ # bool = curia.setfbpsiz(size);
311
+ # Method: Set the size of the free block pool.
312
+ # `size' specifies the size of the free block pool. If it is undef, the free block pool is not
313
+ # used.
314
+ # The return value is always true.
315
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
316
+ # The default size of the free block pool is 16. If the size is greater, the space efficiency
317
+ # of overwriting values is improved with the time efficiency sacrificed.
318
+ #
319
+ def setfbpsiz(size = 0)
320
+ mod_setfbpsiz(@index, size)
321
+ end
322
+ ##
323
+ # bool = curia.sync()
324
+ # Method: Synchronize updating contents with the files and the devices.
325
+ # The return value is always true.
326
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
327
+ # This method is useful when another process uses the connected database directory.
328
+ #
329
+ def sync()
330
+ mod_sync(@index)
331
+ end
332
+ ##
333
+ # bool = curia.optimize(bnum)
334
+ # Method: Optimize the database.
335
+ # `bnum' specifies the number of the elements of the bucket array. If it is omitted or not
336
+ # more than 0, the default value is specified.
337
+ # The return value is always true.
338
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
339
+ # In an alternating succession of deleting and storing with overwrite or concatenate,
340
+ # dispensable regions accumulate. This method is useful to do away with them.
341
+ #
342
+ def optimize(bnum = -1)
343
+ mod_optimize(@index, bnum)
344
+ end
345
+ ##
346
+ # num = curia.fsiz()
347
+ # Method: Get the total size of the database files.
348
+ # The return value is the total size of the database files.
349
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
350
+ # If the total size is more than 2GB, the return value overflows.
351
+ #
352
+ def fsiz()
353
+ mod_fsiz(@index)
354
+ end
355
+ ##
356
+ # num = curia.bnum()
357
+ # Method: Get the total number of the elements of each bucket array.
358
+ # The return value is the total number of the elements of each bucket array
359
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
360
+ #
361
+ def bnum()
362
+ mod_bnum(@index)
363
+ end
364
+ ##
365
+ # num = curia.rnum()
366
+ # Method: Get the number of the records stored in the database.
367
+ # The return value is the number of the records stored in the database.
368
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
369
+ #
370
+ def rnum()
371
+ mod_rnum(@index)
372
+ end
373
+ ##
374
+ # num = curia.length()
375
+ # Method: An alias of `rnum'.
376
+ #
377
+ alias length rnum
378
+ ##
379
+ # num = curia.size()
380
+ # Method: An alias of `rnum'.
381
+ #
382
+ alias size rnum
383
+ ##
384
+ # bool = curia.writable()
385
+ # Method: Check whether the database handle is a writer or not.
386
+ # The return value is true if the handle is a writer, false if not.
387
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
388
+ #
389
+ def writable()
390
+ mod_writable(@index)
391
+ end
392
+ ##
393
+ # bool = curia.fatalerror()
394
+ # Method: Check whether the database has a fatal error or not.
395
+ # The return value is true if the database has a fatal error, false if not.
396
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
397
+ #
398
+ def fatalerror()
399
+ mod_fatalerror(@index)
400
+ end
401
+ ##
402
+ # curia.each() do |key, val| ... end
403
+ # Iterator Method: Iterate a process with a pair of a key and a value of each record.
404
+ #
405
+ def each()
406
+ MyMutex.synchronize() do
407
+ iterinit()
408
+ while(true)
409
+ begin
410
+ break unless key = iternext()
411
+ val = get(key)
412
+ rescue ENOITEM
413
+ break
414
+ end
415
+ yield(key, val)
416
+ end
417
+ iterinit()
418
+ end
419
+ self
420
+ end
421
+ ##
422
+ # curia.each_pair() do |key, val| ... end
423
+ # Iterator Method: An alias of `each'.
424
+ #
425
+ alias each_pair each
426
+ ##
427
+ # curia.each_key() do |key| ... end
428
+ # Iterator Method: Iterate a process with a key of each record.
429
+ #
430
+ def each_key()
431
+ MyMutex.synchronize() do
432
+ iterinit()
433
+ while(true)
434
+ begin
435
+ break unless key = iternext()
436
+ rescue ENOITEM
437
+ break
438
+ end
439
+ yield(key)
440
+ end
441
+ iterinit()
442
+ end
443
+ self
444
+ end
445
+ ##
446
+ # curia.each_value() do |val| ... end
447
+ # Iterator Method: Iterate a process with a value of each record.
448
+ #
449
+ def each_value()
450
+ MyMutex.synchronize() do
451
+ iterinit()
452
+ while(true)
453
+ begin
454
+ break unless key = iternext()
455
+ val = get(key)
456
+ rescue ENOITEM
457
+ break
458
+ end
459
+ yield(val)
460
+ end
461
+ iterinit()
462
+ end
463
+ self
464
+ end
465
+ ##
466
+ # ary = curia.keys()
467
+ # Method: Get an array of all keys.
468
+ # The return value is an array of all keys.
469
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
470
+ #
471
+ def keys()
472
+ ary = Array::new(rnum())
473
+ MyMutex.synchronize() do
474
+ iterinit()
475
+ 0.upto(ary.length - 1) do |i|
476
+ ary[i] = iternext()
477
+ end
478
+ iterinit()
479
+ end
480
+ ary
481
+ end
482
+ ##
483
+ # ary = curia.values()
484
+ # Method: Get an array of all values.
485
+ # The return value is an array of all values.
486
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs.
487
+ #
488
+ def values()
489
+ ary = Array::new(rnum())
490
+ MyMutex.synchronize() do
491
+ iterinit()
492
+ 0.upto(ary.length - 1) do |i|
493
+ ary[i] = get(iternext())
494
+ end
495
+ iterinit()
496
+ end
497
+ ary
498
+ end
499
+ ##
500
+ # str = curia.index(val)
501
+ # Method: Retrieve a record with a value.
502
+ # `val' specifies a value. Although it must be an instance of String, binary data is okey.
503
+ # The return value is the key of the record with the specified value.
504
+ # An exception of `Curia::EANY' or its sub classes is thrown if an error occurs or no record
505
+ # corresponds.
506
+ # If two or more records correspond, the first found record is selected.
507
+ #
508
+ def index(val)
509
+ key = nil
510
+ MyMutex.synchronize() do
511
+ iterinit()
512
+ while(true)
513
+ break unless key = iternext()
514
+ (get(key) == val) && break
515
+ end
516
+ iterinit()
517
+ end
518
+ key
519
+ end
520
+ ##
521
+ # num = curia.to_int()
522
+ # Method: An alias of `rnum'.
523
+ #
524
+ alias to_int rnum
525
+ ##
526
+ # num = curia.to_i()
527
+ # Method: An alias of `to_int'.
528
+ #
529
+ alias to_i to_int
530
+ ##
531
+ # str = curia.to_str()
532
+ # Method: Get string standing for the instance.
533
+ #
534
+ def to_str
535
+ if(@index != -1)
536
+ sprintf("#<Curia:%#x:name=%s:state=open:bnum=%d:rnum=%d>",
537
+ object_id(), @name, bnum(), rnum())
538
+ else
539
+ sprintf("#<Curia:%#x:name=%s:state=closed>", object_id(), @name)
540
+ end
541
+ end
542
+ ##
543
+ # str = curia.to_s()
544
+ # Method: An alias of `to_str'.
545
+ #
546
+ alias to_s to_str
547
+ ##
548
+ # ary = curia.to_ary()
549
+ # Method: Get an array of alternation of each pair of key and value.
550
+ #
551
+ def to_ary
552
+ ary = Array::new(rnum())
553
+ i = 0
554
+ each() do |key, val|
555
+ ary[i] = [key, val]
556
+ i += 1
557
+ end
558
+ ary
559
+ end
560
+ ##
561
+ # ary = curia.to_a()
562
+ # Method: An alias of `to_ary'.
563
+ #
564
+ alias to_a to_ary
565
+ ##
566
+ # hash = curia.to_hash()
567
+ # Method: Get a hash storing all records.
568
+ #
569
+ def to_hash
570
+ hash = Hash::new()
571
+ each() do |key, val|
572
+ hash[key] = val
573
+ end
574
+ hash
575
+ end
576
+ ##
577
+ # hash = curia.to_h()
578
+ # Method: An alias of `to_hash'.
579
+ #
580
+ alias to_h to_hash
581
+ ##
582
+ # str = curia.inspect()
583
+ # Method: An alias of `to_str'.
584
+ #
585
+ alias inspect to_str
586
+ end
587
+
588
+
589
+ #----------------------------------------------------------------
590
+ # Alias definition of class methods
591
+ #----------------------------------------------------------------
592
+ class << Curia
593
+ alias open new
594
+ end
595
+
596
+
597
+
598
+ # END OF FILE