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