VolD 0.1

BabuDirectory.java

Go to the documentation of this file.
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 }