|
VolD 0.1
|
00001 00002 package de.zib.vold.backend; 00003 00004 import de.zib.vold.common.VoldException; 00005 00006 import java.util.Map.Entry; 00007 import java.util.List; 00008 import java.util.LinkedList; 00009 import java.util.Map; 00010 import java.util.HashMap; 00011 00012 import java.util.Properties; 00013 00014 import java.io.UnsupportedEncodingException; 00015 00016 import org.xtreemfs.babudb.*; 00017 import org.xtreemfs.babudb.api.database.*; 00018 import org.xtreemfs.babudb.config.*; 00019 import org.xtreemfs.babudb.api.*; 00020 import org.xtreemfs.babudb.api.exception.*; 00021 00022 import javax.annotation.PostConstruct; 00023 import javax.annotation.PreDestroy; 00024 00025 import org.slf4j.Logger; 00026 import org.slf4j.LoggerFactory; 00027 00043 public class BabuDirectory implements PartitionedDirectoryBackend 00044 { 00045 private Properties props; 00046 private String dbname; 00047 00048 private String enc; 00049 00050 private BabuDB babudb; 00051 private Database db; 00052 private boolean opened; 00053 00054 protected final Logger log = LoggerFactory.getLogger( this.getClass() ); 00055 00068 public BabuDirectory( String basedir, String logdir, String sync, String databasename, String encoding ) 00069 { 00070 props = new java.util.Properties(); 00071 00072 props.setProperty( "babudb.baseDir", basedir ); 00073 props.setProperty( "babudb.logDir", logdir ); 00074 props.setProperty( "babudb.sync", sync ); 00075 00076 this.dbname = databasename; 00077 00078 opened = false; 00079 enc = encoding; 00080 } 00081 00085 public BabuDirectory( ) 00086 { 00087 props = new java.util.Properties(); 00088 00089 this.dbname = null; 00090 00091 opened = false; 00092 enc = "utf-8"; 00093 } 00094 00105 public void setProperty( String key, String value ) 00106 { 00107 props.setProperty( key, value ); 00108 } 00109 00115 public String getProperty( String key ) 00116 { 00117 return props.getProperty( key ); 00118 } 00119 00127 public void setDir( String dir ) 00128 { 00129 setProperty( "babudb.baseDir", dir ); 00130 } 00131 00139 public void setLogDir( String logDir ) 00140 { 00141 setProperty( "babudb.logDir", logDir ); 00142 } 00143 00159 public void setSync( String sync ) 00160 { 00161 setProperty( "babudb.sync", sync ); 00162 } 00163 00176 public void setDatabaseName( String databasename ) 00177 { 00178 this.dbname = databasename; 00179 } 00180 00190 public void setEnc( String enc ) 00191 { 00192 this.enc = enc; 00193 } 00194 00202 @Override 00203 @PostConstruct 00204 public void open( ) 00205 { 00206 // guard 00207 { 00208 if( isopen() ) 00209 { 00210 log.warn( "BabuDirectory: tried to open database twice!" ); 00211 return; 00212 } 00213 00214 if( 00215 null == dbname || 00216 null == getProperty( "babudb.baseDir" ) || 00217 null == getProperty( "babudb.logDir" ) || 00218 null == getProperty( "babudb.sync" ) 00219 ) 00220 { 00221 throw new VoldException( "Need to proper initialize BabuDirectory before opening it! Necessary is setting dir (base directory to store files, created by BabuDB), logDir (directory where logfiles are stored), sync (sync method, see BabuDB docs) and database name." ); 00222 } 00223 } 00224 00225 // create new instance of a babuDB 00226 { 00227 try 00228 { 00229 babudb = BabuDBFactory.createBabuDB( new BabuDBConfig( props ) ); 00230 } 00231 catch( java.io.IOException e ) 00232 { 00233 throw new VoldException( e ); 00234 } 00235 catch( BabuDBException e ) 00236 { 00237 throw new VoldException( e ); 00238 } 00239 } 00240 00241 DatabaseManager manager = babudb.getDatabaseManager (); 00242 00243 // open database 00244 { 00245 try 00246 { 00247 db = manager.getDatabase( dbname ); 00248 } 00249 catch( BabuDBException e ) 00250 { 00251 log.info( "BabuDirectory could not open database: " + e.getMessage() ); 00252 log.info( "BabuDirectory will try to create it..." ); 00253 00254 try 00255 { 00256 db = manager.createDatabase( dbname, 3 ); 00257 } 00258 catch( BabuDBException e2 ) 00259 { 00260 throw new VoldException( e2 ); 00261 } 00262 } 00263 00264 opened = true; 00265 } 00266 00267 log.info( "BabuDirectory opened." ); 00268 } 00269 00277 @Override 00278 @PreDestroy 00279 public void close( ) 00280 { 00281 if( ! isopen() ) 00282 { 00283 log.warn( "Tried to close database while it wasn't open" ); 00284 return; 00285 } 00286 00287 try 00288 { 00289 babudb.shutdown( true ); 00290 } 00291 catch( BabuDBException e ) 00292 { 00293 log.warn( "BabuDirectory could not shutdown: " + e.getMessage() ); 00294 try 00295 { 00296 babudb.shutdown( false ); 00297 } 00298 catch( BabuDBException e2 ) 00299 { 00300 throw new VoldException( "BabuDirectory could even not forcefully shutdown.", e2 ); 00301 } 00302 } 00303 00304 opened = false; 00305 log.info( "BabuDirectory closed." ); 00306 } 00307 00313 @Override 00314 public boolean isopen( ) 00315 { 00316 return opened; 00317 } 00318 00330 @Override 00331 public void insert( int partition, List< String > key, List< String > value ) 00332 { 00333 log.trace( "Insert: " + partition + ":'" + key.toString() + "' -> '" + value.toString() + "'" ); 00334 00335 // guard 00336 { 00337 if( ! isopen() ) 00338 { 00339 throw new VoldException( "Tried to operate on closed database." ); 00340 } 00341 00342 if( partition < 0 ) 00343 { 00344 throw new IllegalArgumentException( "BabuDirectory only has nonnegative partitions, thus " + partition + " is an illegal argument." ); 00345 } 00346 if( null == key ) 00347 { 00348 throw new IllegalArgumentException( "null is no valid key!" ); 00349 } 00350 if( null == value ) 00351 { 00352 throw new IllegalArgumentException( "null is no valid value! Use delete instead, to delete the key!" ); 00353 } 00354 } 00355 00356 byte[] _key = _buildkey( key ); 00357 byte[] _value = _buildkey( value ); 00358 insert( partition, _key, _value ); 00359 } 00360 00369 @Override 00370 public void delete( int partition, List< String > key ) 00371 { 00372 log.trace( "Delete: " + partition + ":'" + key.toString() + "'" ); 00373 00374 byte[] _key; 00375 00376 // guard 00377 { 00378 if( ! isopen() ) 00379 { 00380 throw new VoldException( "Tried to operate on closed database." ); 00381 } 00382 00383 if( partition < 0 ) 00384 { 00385 throw new IllegalArgumentException( "BabuDirectory only has nonnegative partitions, thus " + partition + " is an illegal argument." ); 00386 } 00387 if( null == key ) 00388 { 00389 throw new IllegalArgumentException( "null is no valid key!" ); 00390 } 00391 } 00392 00393 _key = _buildkey( key ); 00394 00395 insert( partition, _key, null ); 00396 } 00397 00407 @Override 00408 public Map< List< String >, List< String > > prefixlookup( int partition, List< String > prefix ) 00409 { 00410 // guard 00411 { 00412 log.trace( "PrefixLookup: " + partition + ":'" + prefix.toString() + "'" ); 00413 00414 if( ! isopen() ) 00415 { 00416 throw new VoldException( "Tried to operate on closed database." ); 00417 } 00418 00419 if( partition < 0 ) 00420 { 00421 throw new IllegalArgumentException( "BabuDirectory only has nonnegative partitions, thus " + partition + " is an illegal argument." ); 00422 } 00423 if( null == prefix ) 00424 { 00425 throw new IllegalArgumentException( "null is no valid key!" ); 00426 } 00427 } 00428 00429 Map< List< String >, List< String > > map = new HashMap< List< String >, List< String > >(); 00430 00431 byte[] _prefix; 00432 _prefix = _buildkey( prefix ); 00433 00434 Map< byte[], byte[] > _map; 00435 _map = prefixlookup( partition, _prefix ); 00436 00437 // transform results from BabuDB 00438 { 00439 for( Entry< byte[], byte[] > entry: _map.entrySet() ) 00440 { 00441 if( null == entry.getKey() || null == entry.getValue() ) 00442 { 00443 throw new VoldException( "Internal error: got null prefix or value from BabuDB." ); 00444 } 00445 map.put( buildkey( entry.getKey() ), buildkey( entry.getValue() ) ); 00446 } 00447 } 00448 00449 return map; 00450 } 00451 00459 private void insert( int partition, byte[] key, byte[] value ) 00460 { 00461 // guard 00462 { 00463 if( partition < 0 ) 00464 { 00465 throw new IllegalArgumentException( "BabuDirectory only has nonnegative partitions, thus " + partition + " is an illegal argument." ); 00466 } 00467 if( null == key ) 00468 { 00469 throw new IllegalArgumentException( "null is no valid key!" ); 00470 } 00471 } 00472 00473 db.singleInsert( partition, key, value, null ); 00474 } 00475 00488 private Map< byte[], byte[] > prefixlookup( int partition, byte[] key ) 00489 { 00490 // guard 00491 { 00492 if( partition < 0 ) 00493 { 00494 throw new IllegalArgumentException( "BabuDirectory only has nonnegative partitions, thus " + partition + " is an illegal argument." ); 00495 } 00496 if( null == key ) 00497 { 00498 throw new IllegalArgumentException( "null is no valid key!" ); 00499 } 00500 } 00501 00502 Map< byte[], byte[] > map = new HashMap< byte[], byte[] >(); 00503 00504 // wait synchronously and return fill list 00505 { 00506 try 00507 { 00508 DatabaseRequestResult< ResultSet< byte[], byte[] > > req; 00509 req = db.prefixLookup( partition, key, null ); 00510 00511 ResultSet< byte[], byte[] > res = req.get( ); 00512 00513 while( res.hasNext() ) 00514 { 00515 Entry< byte[], byte[] > entry = res.next(); 00516 map.put( entry.getKey(), entry.getValue() ); 00517 } 00518 00519 res.free(); 00520 } 00521 catch( BabuDBException e ) 00522 { 00523 throw new VoldException( e ); 00524 } 00525 } 00526 00527 return map; 00528 } 00529 00541 @Override 00542 public List< String > lookup( int partition, List< String > key ) 00543 { 00544 // guard 00545 { 00546 log.trace( "Lookup: " + partition + ":'" + key.toString() + "'" ); 00547 00548 if( ! isopen() ) 00549 { 00550 throw new VoldException( "Tried to operate on closed database." ); 00551 } 00552 00553 if( partition < 0 ) 00554 { 00555 throw new IllegalArgumentException( "BabuDirectory only has nonnegative partitions, thus " + partition + " is an illegal argument" ); 00556 } 00557 if( null == key ) 00558 { 00559 throw new IllegalArgumentException( "null is no valid key!" ); 00560 } 00561 } 00562 00563 byte[] _key = _buildkey( key ); 00564 00565 return buildkey( lookup( partition, _key ) ); 00566 } 00567 00579 private byte[] lookup( int partition, byte[] key ) 00580 { 00581 DatabaseRequestResult< byte[] > req; 00582 00583 req = db.lookup( partition, key, null ); 00584 00585 // wait synchronously and return fill list 00586 { 00587 try 00588 { 00589 return req.get( ); 00590 } 00591 catch( BabuDBException e ) 00592 { 00593 throw new VoldException( e ); 00594 } 00595 } 00596 } 00597 00606 private byte[] _buildkey( List< String > l ) 00607 { 00608 List< String > list = new LinkedList< String >( l ); 00609 00610 if( null == list ) 00611 { 00612 throw new IllegalArgumentException( "Illegal argument null for " + this.getClass().getName() + "._buildkey( list ). " ); 00613 } 00614 00615 // sum up the size first 00616 int size = 0; 00617 { 00618 for( String s: list ) 00619 { 00620 size += s.length()+1; 00621 } 00622 } 00623 00624 if( 0 == size ) 00625 return new byte[0]; 00626 00627 size--; // remove the last '\0' 00628 00629 byte[] result = new byte[ size ]; 00630 00631 // append all strings of list to byte array 00632 { 00633 int offset = 0; 00634 00635 byte[] _s; 00636 00637 try 00638 { 00639 _s = list.remove( 0 ).getBytes( enc ); 00640 } 00641 catch( UnsupportedEncodingException e ) 00642 { 00643 throw new VoldException( e ); 00644 } 00645 00646 byteCopy( result, _s, offset ); 00647 00648 offset += _s.length; 00649 00650 for( String s: list ) 00651 { 00652 result[ offset ] = 0; 00653 offset++; 00654 00655 try 00656 { 00657 _s = s.getBytes( enc ); 00658 } 00659 catch( UnsupportedEncodingException e ) 00660 { 00661 throw new VoldException( e ); 00662 } 00663 00664 byteCopy( result, _s, offset ); 00665 00666 offset += s.length(); 00667 } 00668 } 00669 00670 return result; 00671 } 00672 00681 private List< String > buildkey( byte[] _key ) 00682 { 00683 if( null == _key ) 00684 return null; 00685 00686 List< String > result = new LinkedList< String >(); 00687 00688 int offset = 0; 00689 00690 for( int i = 0; i <= _key.length; ++i ) 00691 { 00692 if( i == _key.length || 0 == _key[ i ] ) 00693 { 00694 try 00695 { 00696 String s = new String( _key, offset, i - offset, enc ); 00697 result.add( s ); 00698 } 00699 catch( UnsupportedEncodingException e ) 00700 { 00701 throw new VoldException( e ); 00702 } 00703 00704 offset = i+1; 00705 } 00706 } 00707 00708 return result; 00709 } 00710 00716 private void byteCopy( byte[] dest, byte[] src, int offset ) 00717 { 00718 if( offset < 0 || dest.length-offset < src.length ) 00719 { 00720 throw new IllegalArgumentException( "Not enough space to copy source to destination at given offset." ); 00721 } 00722 00723 for( int i = 0; i < src.length; ++i ) 00724 { 00725 dest[ offset+i ] = src[ i ]; 00726 } 00727 } 00728 }