1 /*************************************************************************************************
2  * Java API of Villa, the advanced 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 package qdbm;
18 
19 
20 
21 /**
22  * The Java API of Villa, the advanced API of QDBM.
23  * This class depends on the native library `jqdbm'.
24  */
25 public class Villa implements ADBM {
26   //----------------------------------------------------------------
27   // error codes
28   //----------------------------------------------------------------
29   /** error code: no error */
30   public static final int ENOERR = 0;
31   /** error code: with fatal error */
32   public static final int EFATAL = 1;
33   /** error code: invalid mode */
34   public static final int EMODE = 2;
35   /** error code: broken database file */
36   public static final int EBROKEN = 3;
37   /** error code: existing record */
38   public static final int EKEEP = 4;
39   /** error code: no item found */
40   public static final int ENOITEM = 5;
41   /** error code: memory allocation error */
42   public static final int EALLOC = 6;
43   /** error code: memory mapping error */
44   public static final int EMAP = 7;
45   /** error code: open error */
46   public static final int EOPEN = 8;
47   /** error code: close error */
48   public static final int ECLOSE = 9;
49   /** error code: trunc error */
50   public static final int ETRUNC = 10;
51   /** error code: sync error */
52   public static final int ESYNC = 11;
53   /** error code: stat error */
54   public static final int ESTAT = 12;
55   /** error code: seek error */
56   public static final int ESEEK = 13;
57   /** error code: read error */
58   public static final int EREAD = 14;
59   /** error code: write error */
60   public static final int EWRITE = 15;
61   /** error code: lock error */
62   public static final int ELOCK = 16;
63   /** error code: unlink error */
64   public static final int EUNLINK = 17;
65   /** error code: mkdir error */
66   public static final int EMKDIR = 18;
67   /** error code: rmdir error */
68   public static final int ERMDIR = 19;
69   /** error code: miscellaneous error */
70   public static final int EMISC = 20;
71   //----------------------------------------------------------------
72   // open modes
73   //----------------------------------------------------------------
74   /** open mode: open as a reader */
75   public static final int OREADER = 1 << 0;
76   /** open mode: open as a writer */
77   public static final int OWRITER = 1 << 1;
78   /** open mode: writer creating */
79   public static final int OCREAT = 1 << 2;
80   /** open mode: writer truncating */
81   public static final int OTRUNC = 1 << 3;
82   /** open mode: open without locking */
83   public static final int ONOLCK = 1 << 4;
84   /** open mode: lock without blocking */
85   public static final int OLCKNB = 1 << 5;
86   /** open mode: compress leaves with ZLIB */
87   public static final int OZCOMP = 1 << 6;
88   /** open mode: compress leaves with LZO */
89   public static final int OYCOMP = 1 << 7;
90   /** open mode: compress leaves with BZIP2 */
91   public static final int OXCOMP = 1 << 8;
92   //----------------------------------------------------------------
93   // comparing modes
94   //----------------------------------------------------------------
95   /** comparing mode: compare by lexical order */
96   public static final int CMPLEX = 0;
97   /** comparing mode: compare as long integers */
98   public static final int CMPNUM = 1;
99   /** comparing mode: compare as decimal strings */
100   public static final int CMPDEC = 2;
101   /** comparing mode: compare as comparable objects */
102   public static final int CMPOBJ = 3;
103   //----------------------------------------------------------------
104   // write modes
105   //----------------------------------------------------------------
106   /** write mode: overwrite the existing value */
107   public static final int DOVER = 0;
108   /** write mode: keep the existing value */
109   public static final int DKEEP = 1;
110   /** write mode: concatenate values */
111   public static final int DCAT = 2;
112   /** write mode: allow duplication of records */
113   public static final int DDUP = 3;
114   /** write mode: allow duplication with reverse order */
115   public static final int DDUPR = 4;
116   //----------------------------------------------------------------
117   // jump modes
118   //----------------------------------------------------------------
119   /** jump mode: jump mode: step forward */
120   public static final int JFORWARD = 0;
121   /** jump mode: jump mode: step backward */
122   public static final int JBACKWARD = 1;
123   /** insertion mode: overwrite the current record */
124   public static final int CPCURRENT = 0;
125   /** insertion mode: insert before the current record */
126   public static final int CPBEFORE = 1;
127   /** insertion mode: insert after the current record */
128   public static final int CPAFTER = 2;
129   //----------------------------------------------------------------
130   // static initializer
131   //----------------------------------------------------------------
132   static {
133     try {
134       System.loadLibrary("jqdbm");
135     } catch(UnsatisfiedLinkError e){
136       e.printStackTrace();
137     }
vlinit()138     vlinit();
139   }
140   //----------------------------------------------------------------
141   // public static methods
142   //----------------------------------------------------------------
143   /**
144    * Get the version information.
145    * @return the string of the version information.
146    */
version()147   public static synchronized String version(){
148     return vlversion();
149   }
150   /**
151    * Get an error message.
152    * @param ecode an error code.
153    * @return the message string of the error code.
154    */
errmsg(int ecode)155   public static synchronized String errmsg(int ecode){
156     return vlerrmsg(ecode);
157   }
158   /**
159    * Remove a database file.
160    * @param name the name of a database file.
161    * @throws VillaException if an error occurs.
162    */
remove(String name)163   public static void remove(String name) throws VillaException {
164     synchronized(ADBM.class){
165       if(vlremove(name) == 0) throw new VillaException(vlecode());
166     }
167   }
168   //----------------------------------------------------------------
169   // instance fields
170   //----------------------------------------------------------------
171   /** Whether to repress frequent exceptions. */
172   public boolean silent;
173   /** Index of the native table for database handles. */
174   private int index;
175   /** Whether the handle has the transaction or not. */
176   private boolean tran;
177   /** Monitor for mutual exclusion control. */
178   private Object tranmonitor;
179   //----------------------------------------------------------------
180   // public or protected methods
181   //----------------------------------------------------------------
182   /**
183    * Get the database handle.
184    * @param name the name of a database file.
185    * @param omode the connection mode: `Villa.OWRITER' as a writer, `Villa.OREADER' as
186    * a reader.  If the mode is `Villa.OWRITER', the following may be added by bitwise or:
187    * `Villa.OCREAT', which means it creates a new database if not exist, `Villa.OTRUNC',
188    * which means it creates a new database regardless if one exists, `Villa.OZCOMP', which means
189    * leaves in the database are compressed with ZLIB, `Villa.OYCOMP', which means leaves in the
190    * database are compressed with LZO, `Villa.OXCOMP', which means leaves in the database are
191    * compressed with BZIP2.  Both of `Villa.OREADER' and `Villa.OWRITER' can be added to by
192    * bitwise or: `Villa.ONOLCK', which means it opens a database file without file locking, or
193    * `Villa.OLCKNB', which means locking is performed without blocking.
194    * @param cmode the comparing function: `Villa.CMPLEX' comparing keys in lexical order,
195    * `Villa.CMPNUM' comparing keys as numbers of big endian, `Villa.CMPDEC' comparing keys as
196    * decimal strings, `Villa.CMPOBJ' comparing keys as serialized objects implementing
197    * `java.util.Comparable'.  The comparing function should be kept same in the life of a
198    * database.
199    * @note While connecting as a writer, an exclusive lock is invoked to the database file.
200    * While connecting as a reader, a shared lock is invoked to the database file.  The thread
201    * blocks until the lock is achieved.  `Villa.OZCOMP', `Villa.OYCOMP', and `Villa.OXCOMP' are
202    * available only if QDBM was built each with ZLIB, LZO, and BZIP2 enabled.  If `Villa.ONOLCK'
203    * is used, the application is responsible for exclusion control.
204    */
Villa(String name, int omode, int cmode)205   public Villa(String name, int omode, int cmode) throws VillaException {
206     synchronized(ADBM.class){
207       silent = false;
208       if((index = vlopen(name, omode, cmode)) == -1) throw new VillaException(vlecode());
209     }
210     tran = false;
211     tranmonitor = new Object();
212   }
213   /**
214    * Get the database handle as a reader.
215    * The same as `Villa(name, Villa.OREADER, Villa.CMPLEX)'.
216    * @see #Villa(java.lang.String, int, int)
217    */
Villa(String name)218   public Villa(String name) throws VillaException {
219     this(name, OREADER, CMPLEX);
220   }
221   /**
222    * Release the resources.
223    * @note If the database handle is not closed yet, it is closed.  Every database should be
224    * closed explicitly.  Do not cast the duty on the gerbage collection.
225    */
finalize()226   protected void finalize() throws Throwable {
227     try {
228       if(index < 0) return;
229       synchronized(ADBM.class){
230         vlclose(index);
231         index = -1;
232       }
233     } finally {
234       super.finalize();
235     }
236   }
237   /**
238    * Close the database handle.
239    * @throws VillaException if an error occurs.
240    * @note Updating a database is assured to be written when the handle is closed.  If a
241    * writer opens a database but does not close it appropriately, the database will be broken.
242    * If the transaction is activated and not committed, it is aborted.
243    */
close()244   public void close() throws VillaException {
245     if(index < 0) throw new VillaException();
246     synchronized(ADBM.class){
247       int rv = vlclose(index);
248       index = -1;
249       if(rv == 0) throw new VillaException(vlecode());
250     }
251   }
252   /**
253    * Store a record.
254    * @param key a byte array of a key.
255    * @param val a byte array of a value.
256    * @param dmode behavior when the key overlaps, by the following values: `Villa.DOVER',
257    * which means the specified value overwrites the existing one, `Villa.DKEEP', which means
258    * the existing value is kept, `Villa.DCAT', which means the specified value is concatenated
259    * at the end of the existing value, `Villa.DDUP', which means duplication of keys is allowed
260    * and the specified value is added as the last one, `Villa.DDUPR', which means duplication of
261    * keys is allowed and the specified value is added as the first one.
262    * @return always true.  However, if the silent flag is true and replace is cancelled, false is
263    * returned instead of exception.
264    * @throws VillaException if an error occurs or replace is cancelled.
265    * @note The cursor becomes unavailable due to updating database.
266    */
put(byte[] key, byte[] val, int dmode)267   public boolean put(byte[] key, byte[] val, int dmode) throws VillaException {
268     if(index < 0) throw new VillaException();
269     synchronized(ADBM.class){
270       if(vlput(index, key, key.length, val, val.length, dmode) == 0){
271         if(silent && vlecode() == EKEEP) return false;
272         throw new VillaException(vlecode());
273       }
274       return true;
275     }
276   }
277   /**
278    * Store a record with overwrite.
279    * The same as `put(key, val, Villa.DOVER)'.
280    * @see #put(byte[], byte[], int)
281    */
put(byte[] key, byte[] val)282   public boolean put(byte[] key, byte[] val) throws VillaException {
283     return put(key, val, DOVER);
284   }
285   /**
286    * Store a record composed of serializable objects.
287    * The same as `put(qdbm.Util.serialize(key), qdbm.Util.serialize(val), dmode)'.
288    * @see #put(byte[], byte[], int)
289    * @note If serialization is failed, an instance of `VillaException' is thrown.
290    */
putobj(Object key, Object val, int dmode)291   public boolean putobj(Object key, Object val, int dmode) throws VillaException {
292     byte[] kbuf = Util.serialize(key);
293     byte[] vbuf = Util.serialize(val);
294     if(kbuf == null || vbuf == null) throw new VillaException();
295     return put(kbuf, vbuf, dmode);
296   }
297   /**
298    * Delete a record.
299    * @param key a byte array of a key.
300    * @return always true.  However, if the silent flag is true and no record corresponds, false
301    * is returned instead of exception.
302    * @throws VillaException if an error occurs or no record corresponds.
303    * @note When the key of duplicated records is specified, the first record of the same key
304    * is deleted.  The cursor becomes unavailable due to updating database.
305    */
out(byte[] key)306   public boolean out(byte[] key) throws VillaException {
307     if(index < 0) throw new VillaException();
308     synchronized(ADBM.class){
309       if(vlout(index, key, key.length) == 0){
310         if(silent && vlecode() == ENOITEM) return false;
311         throw new VillaException(vlecode());
312       }
313       return true;
314     }
315   }
316   /**
317    * Delete a record composed of serializable objects.
318    * The same as `out(qdbm.Util.serialize(key))'.
319    * @see #out(byte[])
320    * @note If serialization is failed, an instance of `VillaException' is thrown.
321    */
outobj(Object key)322   public boolean outobj(Object key) throws VillaException {
323     byte[] kbuf = Util.serialize(key);
324     if(kbuf == null) throw new VillaException();
325     return out(kbuf);
326   }
327   /**
328    * Retrieve a record.
329    * @param key a byte array of a key.
330    * @return a byte array of the value of the corresponding record.  If the silent flag is true
331    * and no record corresponds, `null' is returned instead of exception.
332    * @throws VillaException if an error occurs, no record corresponds.
333    * @note When the key of duplicated records is specified, the value of the first record of
334    * the same key is selected.
335    */
get(byte[] key)336   public byte[] get(byte[] key) throws VillaException {
337     if(index < 0) throw new VillaException();
338     synchronized(ADBM.class){
339       byte[] val = vlget(index, key, key.length);
340       if(val == null){
341         if(silent && vlecode() == ENOITEM) return null;
342         throw new VillaException(vlecode());
343       }
344       return val;
345     }
346   }
347   /**
348    * Retrieve a record composed of serializable objects.
349    * The same as `qdbm.Util.deserialize(get(qdbm.Util.serialize(key)))'.
350    * @see #get(byte[])
351    * @note If serialization is failed, an instance of `VillaException' is thrown.
352    */
getobj(Object key)353   public Object getobj(Object key) throws VillaException {
354     byte[] kbuf = Util.serialize(key);
355     if(kbuf == null) throw new VillaException();
356     byte[] vbuf = get(kbuf);
357     if(vbuf == null) return null;
358     Object val = Util.deserialize(vbuf);
359     if(val == null) throw new VillaException();
360     return val;
361   }
362   /**
363    * Get the size of the value of a record.
364    * @param key a byte array of a key.
365    * @return the size of the value of the corresponding record.  If multiple records correspond,
366    * the size of the first is returned.  If the silent flag is true and no record corresponds, -1
367    * is returned instead of exception.
368    * @throws VillaException if an error occurs.
369    */
vsiz(byte[] key)370   public int vsiz(byte[] key) throws VillaException {
371     if(index < 0) throw new VillaException();
372     synchronized(ADBM.class){
373       int rv = vlvsiz(index, key, key.length);
374       if(rv == -1){
375         if(silent && vlecode() == ENOITEM) return -1;
376         throw new VillaException(vlecode());
377       }
378       return rv;
379     }
380   }
381   /**
382    * Get the size of the value of a record, composed of serializable objects.
383    * The same as `vsiz(qdbm.Util.serialize(key))'.
384    * @see #vnum(byte[])
385    * @note If serialization is failed, an instance of `VillaException' is thrown.
386    */
vsizobj(Object key)387   public int vsizobj(Object key) throws VillaException {
388     byte[] kbuf = Util.serialize(key);
389     if(kbuf == null) throw new VillaException();
390     return vsiz(kbuf);
391   }
392   /**
393    * Get the number of records corresponding a key.
394    * @param key a byte array of a key.
395    * @return the number of corresponding records.  If no record corresponds, 0 is returned.
396    * @throws VillaException if an error occurs.
397    */
vnum(byte[] key)398   public int vnum(byte[] key) throws VillaException {
399     if(index < 0) throw new VillaException();
400     synchronized(ADBM.class){
401       int rv = vlvnum(index, key, key.length);
402       if(rv == -1) throw new VillaException(vlecode());
403       return rv;
404     }
405   }
406   /**
407    * Get the number of records corresponding a key, composed of serializable objects.
408    * The same as `vnum(qdbm.Util.serialize(key))'.
409    * @see #vnum(byte[])
410    * @note If serialization is failed, an instance of `VillaException' is thrown.
411    */
vnumobj(Object key)412   public int vnumobj(Object key) throws VillaException {
413     byte[] kbuf = Util.serialize(key);
414     if(kbuf == null) throw new VillaException();
415     return vnum(kbuf);
416   }
417   /**
418    * Move the cursor to the first record.
419    * @return always true.  However, if the silent flag is true and no record corresponds, false
420    * is returned instead of exception.
421    * @throws VillaException if an error occurs or there is no record in the database.
422    */
curfirst()423   public boolean curfirst() throws VillaException {
424     if(index < 0) throw new VillaException();
425     synchronized(ADBM.class){
426       if(vlcurfirst(index) == 0){
427         if(silent && vlecode() == ENOITEM) return false;
428         throw new VillaException(vlecode());
429       }
430       return true;
431     }
432   }
433   /**
434    * Move the cursor to the last record.
435    * @return always true.  However, if the silent flag is true and no record corresponds, false
436    * is returned instead of exception.
437    * @throws VillaException if an error occurs or there is no record in the database.
438    */
curlast()439   public boolean curlast() throws VillaException {
440     if(index < 0) throw new VillaException();
441     synchronized(ADBM.class){
442       if(vlcurlast(index) == 0){
443         if(silent && vlecode() == ENOITEM) return false;
444         throw new VillaException(vlecode());
445       }
446       return true;
447     }
448   }
449   /**
450    * Move the cursor to the next record.
451    * @return always true.  However, if the silent flag is true and no record corresponds, false
452    * is returned instead of exception.
453    * @throws VillaException if an error occurs or there is no previous record.
454    */
curprev()455   public boolean curprev() throws VillaException {
456     if(index < 0) throw new VillaException();
457     synchronized(ADBM.class){
458       if(vlcurprev(index) == 0){
459         if(silent && vlecode() == ENOITEM) return false;
460         throw new VillaException(vlecode());
461       }
462       return true;
463     }
464   }
465   /**
466    * Move the cursor to the next record.
467    * @return always true.  However, if the silent flag is true and no record corresponds, false
468    * is returned instead of exception.
469    * @throws VillaException if an error occurs or there is no next record.
470    */
curnext()471   public boolean curnext() throws VillaException {
472     if(index < 0) throw new VillaException();
473     synchronized(ADBM.class){
474       if(vlcurnext(index) == 0){
475         if(silent && vlecode() == ENOITEM) return false;
476         throw new VillaException(vlecode());
477       }
478       return true;
479     }
480   }
481   /**
482    * Move the cursor to a position around a record.
483    * @param key a byte array of a key.
484    * @param jmode detail adjustment: `Villa.JFORWARD', which means that the cursor is set to
485    * the first record of the same key and that the cursor is set to the next substitute if
486    * completely matching record does not exist, `Villa.JBACKWARD', which means that the cursor
487    * is set to the last record of the same key and that the cursor is set to the previous
488    * substitute if completely matching record does not exist.
489    * @return always true.  However, if the silent flag is true and no record corresponds, false
490    * is returned instead of exception.
491    * @throws VillaException if an error occurs or there is no record corresponding the condition.
492    */
curjump(byte[] key, int jmode)493   public boolean curjump(byte[] key, int jmode) throws VillaException {
494     if(index < 0) throw new VillaException();
495     synchronized(ADBM.class){
496       if(vlcurjump(index, key, key.length, jmode) == 0){
497         if(silent && vlecode() == ENOITEM) return false;
498         throw new VillaException(vlecode());
499       }
500       return true;
501     }
502   }
503   /**
504    * Move the cursor to a position around a record for stepping forward.
505    * The same as `curjump(key, Villa.JFORFARD)'.
506    * @see #curjump(byte[], int)
507    */
curjump(byte[] key)508   public boolean curjump(byte[] key) throws VillaException {
509     return curjump(key, JFORWARD);
510   }
511   /**
512    * Move the cursor to a position around a record composed of serializable objects.
513    * The same as `curjump(qdbm.Util.serialize(key), jmode)'.
514    * @see #curjump(byte[], int)
515    * @note If serialization is failed, an instance of `VillaException' is thrown.
516    */
curjumpobj(Object key, int jmode)517   public boolean curjumpobj(Object key, int jmode) throws VillaException {
518     byte[] kbuf = Util.serialize(key);
519     if(kbuf == null) throw new VillaException();
520     return curjump(kbuf, jmode);
521   }
522   /**
523    * Get the key of the record where the cursor is.
524    * @return a byte array of the key of the corresponding record.  If the silent flag is true and
525    * no record corresponds, `null' is returned instead of exception.
526    * @throws VillaException if an error occurs or no record corresponds to the cursor.
527    */
curkey()528   public byte[] curkey() throws VillaException {
529     if(index < 0) throw new VillaException();
530     synchronized(ADBM.class){
531       byte[] val = vlcurkey(index);
532       if(val == null){
533         if(silent && vlecode() == ENOITEM) return null;
534         throw new VillaException(vlecode());
535       }
536       return val;
537     }
538   }
539   /**
540    * Get the key of the record composed of serializable objects, where the cursor is.
541    * The same as `qdbm.Util.deserialize(curkey())'.
542    * @see #curkey()
543    * @note If serialization is failed, an instance of `VillaException' is thrown.
544    */
curkeyobj()545   public Object curkeyobj() throws VillaException {
546     byte[] kbuf = curkey();
547     if(kbuf == null) return null;
548     Object key = Util.deserialize(kbuf);
549     if(key == null) throw new VillaException();
550     return key;
551   }
552   /**
553    * Get the value of the record where the cursor is.
554    * @return a byte array of the value of the corresponding record.  If the silent flag is true
555    * and no record corresponds, `null' is returned instead of exception.
556    * @throws VillaException if an error occurs or no record corresponds to the cursor.
557    */
curval()558   public byte[] curval() throws VillaException {
559     if(index < 0) throw new VillaException();
560     synchronized(ADBM.class){
561       byte[] val = vlcurval(index);
562       if(val == null){
563         if(silent && vlecode() == ENOITEM) return null;
564         throw new VillaException(vlecode());
565       }
566       return val;
567     }
568   }
569   /**
570    * Get the value of the record where the cursor is.
571    * The same as `qdbm.Util.deserialize(curval())'.
572    * @see #curval()
573    * @note If serialization is failed, an instance of `VillaException' is thrown.
574    */
curvalobj()575   public Object curvalobj() throws VillaException {
576     byte[] vbuf = curval();
577     if(vbuf == null) return null;
578     Object val = Util.deserialize(vbuf);
579     if(val == null) throw new VillaException();
580     return val;
581   }
582   /**
583    * Insert a record around the cursor.
584    * @param val a byte array of a value.
585    * @param cpmode detail adjustment: `Villa.CPCURRENT', which means that the value of the
586    * current record is overwritten, `Villa.CPBEFORE', which means that a new record is inserted
587    * before the current record, `Villa.CPAFTER', which means that a new record is inserted after
588    * the current record.
589    * @return always true.  However, if the silent flag is true and no record corresponds to the
590    * cursor, false is returned instead of exception.
591    * @throws VillaException if an error occurs or no record corresponds to the cursor.
592    * @note After insertion, the cursor is moved to the inserted record.
593    */
curput(byte[] val, int cpmode)594   public boolean curput(byte[] val, int cpmode) throws VillaException {
595     if(index < 0) throw new VillaException();
596     synchronized(ADBM.class){
597       if(vlcurput(index, val, val.length, cpmode) == 0){
598         if(silent && vlecode() == ENOITEM) return false;
599         throw new VillaException(vlecode());
600       }
601       return true;
602     }
603   }
604   /**
605    * Insert a record as the successor of the cursor.
606    * The same as `curput(val, Villa.CPCURRENT)'.
607    * @see #curput(byte[], int)
608    */
curput(byte[] val)609   public boolean curput(byte[] val) throws VillaException {
610     return curput(val, CPCURRENT);
611   }
612   /**
613    * Insert a record around the cursor.
614    * The same as `curput(qdbm.Util.serialize(val), cpmode)'.
615    * @see #curput(byte[], int)
616    */
curputobj(Object val, int cpmode)617   public boolean curputobj(Object val, int cpmode) throws VillaException {
618     byte[] vbuf = Util.serialize(val);
619     if(vbuf == null) throw new VillaException();
620     return curput(vbuf, cpmode);
621   }
622   /**
623    * Delete the record where the cursor is.
624    * @return always true.  However, if the silent flag is true and no record corresponds to the
625    * cursor, false is returned instead of exception.
626    * @throws VillaException if an error occurs or no record corresponds to the cursor.
627    * @note After deletion, the cursor is moved to the next record if possible.
628    */
curout()629   public boolean curout() throws VillaException {
630     if(index < 0) throw new VillaException();
631     synchronized(ADBM.class){
632       if(vlcurout(index) == 0){
633         if(silent && vlecode() == ENOITEM) return false;
634         throw new VillaException(vlecode());
635       }
636       return true;
637     }
638   }
639   /**
640    * Set the tuning parameters for performance.
641    * @param lrecmax the max number of records in a leaf node of B+ tree.  If it is not more
642    * than 0, the default value is specified.
643    * @param nidxmax the max number of indexes in a non-leaf node of B+ tree.  If it is not more
644    * than 0, the default value is specified.
645    * @param lcnum the max number of caching leaf nodes.  If it is not more than 0, the default
646    * value is specified.
647    * @param ncnum the max number of caching non-leaf nodes.  If it is not more than 0, the
648    * default value is specified.
649    * @throws VillaException if an error occurs.
650    * @note The default setting is equivalent to `settuning(49, 192, 1024, 512)'.  Because tuning
651    * parameters are not saved in a database, you should specify them every opening a database.
652    */
settuning(int lrecmax, int nidxmax, int lcnum, int ncnum)653   public void settuning(int lrecmax, int nidxmax, int lcnum, int ncnum) throws VillaException {
654     if(index < 0) throw new VillaException();
655     synchronized(ADBM.class){
656       vlsettuning(index, lrecmax, nidxmax, lcnum, ncnum);
657     }
658   }
659   /**
660    * Synchronize updating contents with the file and the device.
661    * @throws VillaException if an error occurs.
662    * @note This method is useful when another process uses the connected database file.  This
663    * method should not be used while the transaction is activated.
664    */
sync()665   public void sync() throws VillaException {
666     if(index < 0) throw new VillaException();
667     synchronized(ADBM.class){
668       if(vlsync(index) == 0) throw new VillaException(vlecode());
669     }
670   }
671   /**
672    * Optimize the database.
673    * @throws VillaException if an error occurs.
674    * @note In an alternating succession of deleting and storing with overwrite or concatenate,
675    * dispensable regions accumulate.  This method is useful to do away with them.  This method
676    * should not be used while the transaction is activated.
677    */
optimize()678   public void optimize() throws VillaException {
679     if(index < 0) throw new VillaException();
680     synchronized(ADBM.class){
681       if(vloptimize(index) == 0) throw new VillaException(vlecode());
682     }
683   }
684   /**
685    * Get the name of the database.
686    * @return the string of the name of the database.
687    * @throws VillaException if an error occurs.
688    */
name()689   public String name() throws VillaException {
690     if(index < 0) throw new VillaException();
691     synchronized(ADBM.class){
692       String buf = vlname(index);
693       if(buf == null) throw new VillaException(vlecode());
694       return buf;
695     }
696   }
697   /**
698    * Get the size of the database file.
699    * @return the size of the database file.
700    * @throws VillaException if an error occurs.
701    * @note Because of the I/O buffer, the return value may be less than the real size.
702    */
fsiz()703   public int fsiz() throws VillaException {
704     if(index < 0) throw new VillaException();
705     synchronized(ADBM.class){
706       int rv = vlfsiz(index);
707       if(rv == -1) throw new VillaException(vlecode());
708       return rv;
709     }
710   }
711   /**
712    * Get the number of the leaf nodes of B+ tree.
713    * @return the number of the leaf nodes.
714    * @throws VillaException if an error occurs.
715    */
lnum()716   public int lnum() throws VillaException {
717     if(index < 0) throw new VillaException();
718     synchronized(ADBM.class){
719       int rv = vllnum(index);
720       if(rv == -1) throw new VillaException(vlecode());
721       return rv;
722     }
723   }
724   /**
725    * Get the number of the non-leaf nodes of B+ tree.
726    * @return the number of the non-leaf nodes.
727    * @throws VillaException if an error occurs.
728    */
nnum()729   public int nnum() throws VillaException {
730     if(index < 0) throw new VillaException();
731     synchronized(ADBM.class){
732       int rv = vlnnum(index);
733       if(rv == -1) throw new VillaException(vlecode());
734       return rv;
735     }
736   }
737   /**
738    * Get the number of the records stored in a database.
739    * @return the number of the records stored in the database.
740    * @throws VillaException if an error occurs.
741    */
rnum()742   public int rnum() throws VillaException {
743     if(index < 0) throw new VillaException();
744     synchronized(ADBM.class){
745       int rv = vlrnum(index);
746       if(rv == -1) throw new VillaException(vlecode());
747       return rv;
748     }
749   }
750   /**
751    * Check whether the database handle is a writer or not.
752    * @return true if the handle is a writer, false if not.
753    * @throws VillaException if an error occurs.
754    */
writable()755   public boolean writable() throws VillaException {
756     if(index < 0) throw new VillaException();
757     synchronized(ADBM.class){
758       return vlwritable(index) == 0 ? false : true;
759     }
760   }
761   /**
762    * Check whether the database has a fatal error or not.
763    * @return true if the database has a fatal error, false if not.
764    * @throws VillaException if an error occurs.
765    */
fatalerror()766   public boolean fatalerror() throws VillaException {
767     if(index < 0) throw new VillaException();
768     synchronized(ADBM.class){
769       return vlfatalerror(index) == 0 ? false : true;
770     }
771   }
772   /**
773    * Get the inode number of the database.
774    * @return the inode number of the database file.
775    * @throws VillaException if an error occurs.
776    */
inode()777   public int inode() throws VillaException {
778     if(index < 0) throw new VillaException();
779     synchronized(ADBM.class){
780       return vlinode(index);
781     }
782   }
783   /**
784    * Get the last modified time of the database.
785    * @return the last modified time of the database.
786    * @throws VillaException if an error occurs.
787    */
mtime()788   public long mtime() throws VillaException {
789     if(index < 0) throw new VillaException();
790     synchronized(ADBM.class){
791       return vlmtime(index);
792     }
793   }
794   /**
795    * Begin the transaction.
796    * @throws VillaException if an error occurs.
797    * @note If a thread is already in the transaction, the other threads block until the prius
798    * is out of the transaction.  Only one transaction can be activated with a database handle
799    * at the same time.
800    */
tranbegin()801   public void tranbegin() throws VillaException {
802     if(index < 0) throw new VillaException();
803     synchronized(tranmonitor){
804       while(tran){
805         try {
806           tranmonitor.wait();
807         } catch(InterruptedException e){
808           e.printStackTrace();
809           throw new VillaException();
810         }
811       }
812       tran = true;
813     }
814     synchronized(ADBM.class){
815       if(vltranbegin(index) == 0){
816         tran = false;
817         throw new VillaException(vlecode());
818       }
819     }
820   }
821   /**
822    * Commit the transaction.
823    * @throws VillaException if an error occurs.
824    * @note Updating a database in the transaction is fixed when it is committed successfully.
825    * Any other thread except for the one which began the transaction should not call this method.
826    */
trancommit()827   public void trancommit() throws VillaException {
828     if(index < 0) throw new VillaException();
829     synchronized(ADBM.class){
830       if(vltrancommit(index) == 0){
831         synchronized(tranmonitor){
832           tran = false;
833           tranmonitor.notify();
834         }
835         throw new VillaException(vlecode());
836       }
837     }
838     synchronized(tranmonitor){
839       tran = false;
840       tranmonitor.notify();
841     }
842   }
843   /**
844    * Abort the transaction.
845    * @throws VillaException if an error occurs.
846    * @note Updating a database in the transaction is discarded when it is aborted.  The state
847    * of the database is rollbacked to before transaction.  Any other thread except for the one
848    * which began the transaction should not call this method.
849    */
tranabort()850   public void tranabort() throws VillaException {
851     if(index < 0) throw new VillaException();
852     synchronized(ADBM.class){
853       if(vltranabort(index) == 0){
854         synchronized(tranmonitor){
855           tran = false;
856           tranmonitor.notify();
857         }
858         throw new VillaException(vlecode());
859       }
860     }
861     synchronized(tranmonitor){
862       tran = false;
863       tranmonitor.notify();
864     }
865   }
866   /**
867    * Store a record.
868    * @param key a byte array of a key.
869    * @param val a byte array of a value.
870    * @param replace whether the existing value is to be overwritten or not.
871    * @throws VillaException if an error occurs or replace is cancelled.
872    */
store(byte[] key, byte[] val, boolean replace)873   public void store(byte[] key, byte[] val, boolean replace) throws VillaException {
874     if(!put(key, val, replace ? DOVER : DKEEP)) throw new VillaException(EKEEP);
875   }
876   /**
877    * Delete a record.
878    * @param key a byte array of a key.
879    * @throws VillaException if an error occurs or no record corresponds.
880    */
delete(byte[] key)881   public void delete(byte[] key) throws VillaException {
882     if(!out(key)) throw new VillaException(ENOITEM);
883   }
884   /**
885    * Fetch a record.
886    * @param key a byte array of a key.
887    * @return a byte array of the value of the corresponding record.
888    * @throws VillaException if an error occurs or no record corresponds.
889    */
fetch(byte[] key)890   public byte[] fetch(byte[] key) throws VillaException {
891     byte[] vbuf = get(key);
892     if(vbuf == null) throw new VillaException(ENOITEM);
893     return vbuf;
894   }
895   /**
896    * Get the first key.
897    * @return a byte array of the key of the first record.
898    * @throws VillaException if an error occurs or no record corresponds.
899    */
firstkey()900   public byte[] firstkey() throws VillaException {
901     curfirst();
902     byte[] kbuf = curkey();
903     if(kbuf == null) throw new VillaException(ENOITEM);
904     return kbuf;
905   }
906   /**
907    * Get the next key.
908    * @return a byte array of the key of the next record.
909    * @throws VillaException if an error occurs or no record corresponds.
910    */
nextkey()911   public byte[] nextkey() throws VillaException {
912     curnext();
913     byte[] kbuf = curkey();
914     if(kbuf == null) throw new VillaException(ENOITEM);
915     return kbuf;
916   }
917   /**
918    * Check whether a fatal error occured or not.
919    * @return true if the database has a fatal error, false if not.
920    * @throws VillaException if an error occurs.
921    */
error()922   public boolean error() throws VillaException {
923     return fatalerror();
924   }
925   /**
926    * Get a multiple cursor.
927    * @return a multiple cursor.
928    * @note Even if plural cursors are fetched out of a database handle, they does not share the
929    * locations with each other.  Note that this method can be used only if the database handle
930    * is connected as a reader.
931    */
mulcuropen()932   public VillaCursor mulcuropen() throws VillaException {
933     return new VillaCursor(this);
934   }
935   //----------------------------------------------------------------
936   // friendly methods
937   //----------------------------------------------------------------
938   /**
939    * Get the index of the native table for database handles.
940    * @return the index of the native table for database handles.
941    */
getindex()942   public int getindex(){
943     return index;
944   }
945   //----------------------------------------------------------------
946   // private static methods
947   //----------------------------------------------------------------
948   /**
949    * Compare keys of two records as serialized objects implementing `java.util.Comparable'.
950    * @param abuf serialized data of one object.
951    * @param bbuf serialized data of the other object.
952    * @return positive if the former is big, negative if the latter is big, 0 if both are
953    * equivalent.
954    */
objcompare(byte[] abuf, byte[] bbuf)955   private static final int objcompare(byte[] abuf, byte[] bbuf){
956     Object a = Util.deserialize(abuf);
957     Object b = Util.deserialize(bbuf);
958     if(a != null && b == null) return 1;
959     if(a == null && b != null) return -1;
960     if(a == null && b == null) return 0;
961     try {
962       return ((Comparable)a).compareTo(b);
963     } catch(ClassCastException e){
964       return 0;
965     }
966   }
967   //----------------------------------------------------------------
968   // native methods
969   //----------------------------------------------------------------
vlinit()970   private static synchronized final native void vlinit();
vlversion()971   private static synchronized final native String vlversion();
vlecode()972   private static synchronized final native int vlecode();
vlerrmsg(int ecode)973   private static synchronized final native String vlerrmsg(int ecode);
974 
vlopen(String name, int omode, int cmode)975   private static synchronized final native int vlopen(String name, int omode, int cmode);
vlclose(int index)976   private static synchronized final native int vlclose(int index);
vlput(int index, byte[] key, int ksiz, byte[] val, int vsiz, int dmode)977   private static synchronized final native int vlput(int index, byte[] key, int ksiz,
978                                                      byte[] val, int vsiz, int dmode);
vlout(int index, byte[] key, int ksiz)979   private static synchronized final native int vlout(int index, byte[] key, int ksiz);
vlget(int index, byte[] key, int ksiz)980   private static synchronized final native byte[] vlget(int index, byte[] key, int ksiz);
vlvsiz(int index, byte[] key, int ksiz)981   private static synchronized final native int vlvsiz(int index, byte[] key, int ksiz);
vlvnum(int index, byte[] key, int ksiz)982   private static synchronized final native int vlvnum(int index, byte[] key, int ksiz);
vlcurfirst(int index)983   private static synchronized final native int vlcurfirst(int index);
vlcurlast(int index)984   private static synchronized final native int vlcurlast(int index);
vlcurprev(int index)985   private static synchronized final native int vlcurprev(int index);
vlcurnext(int index)986   private static synchronized final native int vlcurnext(int index);
vlcurjump(int index, byte[] key, int ksiz, int jmode)987   private static synchronized final native int vlcurjump(int index, byte[] key, int ksiz,
988                                                          int jmode);
vlcurkey(int index)989   private static synchronized final native byte[] vlcurkey(int index);
vlcurval(int index)990   private static synchronized final native byte[] vlcurval(int index);
vlcurput(int index, byte[] val, int vsiz, int cpmode)991   private static synchronized final native int vlcurput(int index, byte[] val, int vsiz,
992                                                         int cpmode);
vlcurout(int index)993   private static synchronized final native int vlcurout(int index);
vlsettuning(int index, int lrecmax, int nidxmax, int lcnum, int ncnum)994   private static synchronized final native void vlsettuning(int index, int lrecmax, int nidxmax,
995                                                             int lcnum, int ncnum);
vlsync(int index)996   private static synchronized final native int vlsync(int index);
vloptimize(int index)997   private static synchronized final native int vloptimize(int index);
vlname(int index)998   private static synchronized final native String vlname(int index);
vlfsiz(int index)999   private static synchronized final native int vlfsiz(int index);
vllnum(int index)1000   private static synchronized final native int vllnum(int index);
vlnnum(int index)1001   private static synchronized final native int vlnnum(int index);
vlrnum(int index)1002   private static synchronized final native int vlrnum(int index);
vlwritable(int index)1003   private static synchronized final native int vlwritable(int index);
vlfatalerror(int index)1004   private static synchronized final native int vlfatalerror(int index);
vlinode(int index)1005   private static synchronized final native int vlinode(int index);
vlmtime(int index)1006   private static synchronized final native long vlmtime(int index);
vltranbegin(int index)1007   private static synchronized final native int vltranbegin(int index);
vltrancommit(int index)1008   private static synchronized final native int vltrancommit(int index);
vltranabort(int index)1009   private static synchronized final native int vltranabort(int index);
vlremove(String name)1010   private static synchronized final native int vlremove(String name);
1011 }
1012 
1013 
1014 
1015 /* END OF FILE */
1016