VolD 0.1

VolatileDirectoryImpl.java

Go to the documentation of this file.
00001 
00002 package de.zib.vold.volatilelogic;
00003 
00004 import de.zib.vold.backend.PartitionedDirectory;
00005 import de.zib.vold.backend.NotSupportedException;
00006 
00007 import java.util.List;
00008 import java.util.LinkedList;
00009 import java.util.Set;
00010 import java.util.HashSet;
00011 import java.util.Map;
00012 import java.util.HashMap;
00013 
00014 import org.joda.time.DateTime;
00015 
00016 import org.slf4j.Logger;
00017 import org.slf4j.LoggerFactory;
00018 
00042 public class VolatileDirectoryImpl implements VolatileDirectory
00043 {
00044         private PartitionedDirectory directory;
00045         private TimeSlice timeslice;
00046 
00047         protected final Logger log = LoggerFactory.getLogger( this.getClass() );
00048 
00055         public VolatileDirectoryImpl( PartitionedDirectory backend, TimeSlice timeslice )
00056         {
00057                 this.directory = backend;
00058                 this.timeslice = timeslice;
00059         }
00060 
00064         public VolatileDirectoryImpl( )
00065         {
00066                 this.directory = null;
00067                 this.timeslice = null;
00068         }
00069 
00073         protected void checkState( )
00074         {
00075                 if( null == timeslice || null == directory )
00076                 {
00077                         throw new IllegalStateException( "Tried to operate on database while it had not been initialized yet. You first need to set a TimeSlice and Directory backend!" );
00078                 }
00079         }
00080 
00086         public void setTimeslice( TimeSlice timeslice )
00087         {
00088                 if( null != this.timeslice )
00089                 {
00090                         log.warn( "Resetting the timeslice can lead to lost keys (they will never be deleted by the reaper!)" );
00091                 }
00092 
00093                 this.timeslice = timeslice;
00094         }
00095 
00099         public void setBackend( PartitionedDirectory backend )
00100         {
00101                 this.directory = backend;
00102         }
00103 
00109         @Override
00110         public long getActualSlice( )
00111         {
00112                 // guard
00113                 {
00114                         checkState();
00115                 }
00116 
00117                 return timeslice.getActualSlice();
00118         }
00119 
00125         @Override
00126         public long getNumberOfSlices( )
00127         {
00128                 // guard
00129                 {
00130                         checkState();
00131                 }
00132 
00133                 return timeslice.getNumberOfSlices();
00134         }
00135 
00141         @Override
00142         public long getTimeSliceSize( )
00143         {
00144                 // guard
00145                 {
00146                         checkState();
00147                 }
00148 
00149                 return timeslice.getTimeSliceSize();
00150         }
00151 
00164         @Override
00165         public void insert( List< String > key, Set< String > value )
00166         {
00167                 // guard
00168                 {
00169                         log.trace( "Insert: '" + key.toString() + "' |--> '" + value.toString() + "'" );
00170 
00171                         checkState();
00172 
00173                         if( null == key )
00174                         {
00175                                 throw new IllegalArgumentException( "Tried to null as key!" );
00176                         }
00177                         if( null == value )
00178                         {
00179                                 throw new IllegalArgumentException( "Tried to insert key " + key.toString() + " with null value. Use delete( key ) instead!" );
00180                         }
00181                 }
00182 
00183                 List< String > oldtimeslice;
00184                 try
00185                 {
00186                         oldtimeslice = directory.lookup( 1, key );
00187                 }
00188                 // insert "key |--> value" entry only, if backend is write only
00189                 catch( NotSupportedException e )
00190                 {
00191                         log.debug( "Backend is write-only. Performing pure insert..." );
00192 
00193                         directory.insert( 0, key, new LinkedList< String >( value ) );
00194                         return;
00195                 }
00196                 
00197                 long newtimeslice = timeslice.getActualSlice();
00198 
00199                 // insert new "slice/key |--> date" entry
00200                 {
00201                         List< String > timeslicekey = get_timeslice_key( newtimeslice, key );
00202 
00203                         directory.insert( 2, timeslicekey, to_date( DateTime.now() ) );
00204                 }
00205 
00206                 // insert "key |--> timeslice" entry
00207                 {
00208                         directory.insert( 1, key, to_value( newtimeslice ) );
00209                 }
00210 
00211                 // insert "key |--> value" entry
00212                 {
00213                         directory.insert( 0, key, new LinkedList< String >( value ) );
00214                 }
00215 
00216                 // delete old "slice/key |--> date" entry
00217                 {
00218                         if( null != oldtimeslice )
00219                         {
00220                                 long oldts = to_timeslice( oldtimeslice );
00221 
00222                                 if( oldts != newtimeslice )
00223                                         directory.delete( 2, get_timeslice_key( to_timeslice( oldtimeslice ), key ) );
00224                         }
00225                 }
00226         }
00227 
00243         @Override
00244         public void refresh( List< String > key )
00245         {
00246                 // guard
00247                 {
00248                         log.trace( "Refresh: " + key.toString() );
00249 
00250                         checkState();
00251 
00252                         if( null == key )
00253                         {
00254                                 throw new IllegalArgumentException( "SimpleDirectory.delete excepts key to be not null!" );
00255                         }
00256                 }
00257 
00258                 List< String > oldtimeslice;
00259                 try
00260                 {
00261                         oldtimeslice = directory.lookup( 1, key );
00262                 }
00263                 // insert "key |--> value" entry only, if backend is write only
00264                 catch( NotSupportedException e )
00265                 {
00266                         log.debug( "Backend is write-only. Performing pure insert..." );
00267 
00268                         directory.insert( 0, key, new LinkedList< String >( ) );
00269                         return;
00270                 }
00271                 
00272                 long newtimeslice = timeslice.getActualSlice();
00273 
00274                 // insert new "slice/key |--> date" entry
00275                 {
00276                         List< String > timeslicekey = get_timeslice_key( newtimeslice, key );
00277 
00278                         directory.insert( 2, timeslicekey, to_date( DateTime.now() ) );
00279                 }
00280 
00281                 // insert "key |--> timeslice" entry
00282                 {
00283                         directory.insert( 1, key, to_value( newtimeslice ) );
00284                 }
00285 
00286                 // delete old "slice/key |--> date" entry
00287                 {
00288                         if( null != oldtimeslice )
00289                         {
00290                                 long oldts = to_timeslice( oldtimeslice );
00291 
00292                                 if( oldts != newtimeslice )
00293                                         directory.delete( 2, get_timeslice_key( to_timeslice( oldtimeslice ), key ) );
00294                         }
00295                 }
00296         }
00297 
00306         @Override
00307         public void delete( List< String > key )
00308         {
00309                 // guard
00310                 {
00311                         log.trace( "Delete: " + key.toString() );
00312 
00313                         checkState();
00314 
00315                         if( null == key )
00316                         {
00317                                 throw new IllegalArgumentException( "SimpleDirectory.delete excepts key to be not null!" );
00318                         }
00319                 }
00320 
00321                 List< String > oldtimeslice = directory.lookup( 1, key );
00322 
00323                 // delete "key |--> value" entry
00324                 {
00325                         directory.delete( 0, key );
00326                 }
00327                 
00328                 // delete "key |--> timeslice" entry
00329                 {
00330                         directory.delete( 1, key );
00331                 }
00332 
00333                 // delete old "slice/key |--> date" entry
00334                 {
00335                         if( null != oldtimeslice )
00336                         {
00337                                 directory.delete( 2, get_timeslice_key( to_timeslice( oldtimeslice ), key ) );
00338                         }
00339                 }
00340         }
00341 
00347         @Override
00348         public Set< String > lookup( List< String > key )
00349         {
00350                 // guard
00351                 {
00352                         log.trace( "Lookup: " + key );
00353 
00354                         checkState();
00355                 }
00356 
00357                 List< String > _result = directory.lookup( 0, key );
00358                 if ( null == _result )
00359                         return null;
00360                 else
00361                         return new HashSet< String >( _result );
00362         }
00363 
00370         @Override
00371         public Map< List< String >, Set< String > > prefixLookup( List< String > key )
00372         {
00373                 // guard
00374                 {
00375                         log.trace( "PrefixLookup: " + key.toString() );
00376 
00377                         checkState();
00378                 }
00379 
00380                 Map< List< String >, List< String > > _result = directory.prefixlookup( 0, key );
00381                 if ( null == _result )
00382                         return null;
00383 
00384                 // convert from Map< List, List > to Map< List, Set >
00385                 {
00386                         Map< List< String >, Set< String > > result = new HashMap< List< String >, Set< String > >();
00387 
00388                         for( Map.Entry< List< String >, List< String > > entry: _result.entrySet() )
00389                         {
00390                                 result.put( entry.getKey(), new HashSet< String >( entry.getValue() ) );
00391                         }
00392 
00393                         return result;
00394                 }
00395         }
00396 
00403         @Override
00404         public Map< List< String >, DateTime > sliceLookup( long slice )
00405         {
00406                 // guard
00407                 {
00408                         log.trace( "SliceLookup: " + slice );
00409 
00410                         checkState();
00411 
00412                         if( slice < 0 )
00413                         {
00414                                 throw new IllegalArgumentException( "Negative slices are not allowed!" );
00415                         }
00416                 }
00417 
00418                 Map< List< String >, List< String > > map;
00419                 Map< List< String >, DateTime > result = new HashMap< List< String >, DateTime >();
00420 
00421                 // get all "timeslice/key |--> date" entries
00422                 {
00423                         // use an empty key to not get "17" when searching for timeslice "1"..
00424                         map = directory.prefixlookup(
00425                                 2,
00426                                 get_timeslice_key( slice, new LinkedList< String >() ) );
00427 
00428                         if( null == map )
00429                         {
00430                                 return null;
00431                         }
00432                 }
00433 
00434                 // remove all timeslice prefixes from keys, thus having a "key |--> date" mapping
00435                 // then, convert the date
00436                 {
00437                         for( Map.Entry< List< String >, List< String > > entry: map.entrySet() )
00438                         {
00439                                 if( entry.getKey().size() < 1 )
00440                                 {
00441                                         log.error( "Internal Error: found a 'slice/key |--> date' mapping with empty slice/key. This should not be possible! Simply skipping entry..." );
00442                                         continue;
00443                                 }
00444 
00445                                 // remove timeslice
00446                                 entry.getKey().remove( 0 );
00447 
00448                                 // convert date
00449                                 try
00450                                 {
00451                                         result.put( entry.getKey(), to_date( entry.getValue() ) );
00452                                 }
00453                                 catch( Exception e )
00454                                 {
00455                                         log.error( "Internal Error: In slice " + slice + ", the Key " + entry.getKey().toString() + " maps to the nonvalid date entry " + entry.getValue().toString() + ". Simply skipping entry..." );
00456                                         continue;
00457                                 }
00458                         }
00459                 }
00460 
00461                 return result;
00462         }
00463 
00474         private DateTime to_date( List< String > date )
00475         {
00476                 if( 1 != date.size() )
00477                 {
00478                         throw new IllegalArgumentException( "Parameter date must be a list of size one!" );
00479                 }
00480 
00481                 return new DateTime( Long.parseLong( date.get( 0 ) ) );
00482         }
00483 
00490         private List< String > to_date( DateTime date )
00491         {
00492                 List< String > result = new LinkedList< String >();
00493                 result.add( String.valueOf( date.getMillis() ) );
00494                 return result;
00495         }
00496 
00505         private long to_timeslice( List< String > slice )
00506         {
00507                 if( 1 != slice.size() )
00508                 {
00509                         throw new IllegalArgumentException( "The parameter must be a list with one String! (" + slice.toString() + ")" );
00510                 }
00511 
00512                 return Long.parseLong( slice.get( 0 ) );
00513         }
00514 
00526         private List< String > get_timeslice_key( long slice, List< String > key )
00527         {
00528                 if( slice < 0 )
00529                 {
00530                         throw new IllegalArgumentException( "Negative slices are not allowed!" );
00531                 }
00532 
00533                 List< String > timeslicekey = new LinkedList< String >( key );
00534                 timeslicekey.add( 0, String.valueOf( slice ) );
00535 
00536                 return timeslicekey;
00537         }
00538 
00545         private List< String > to_value( long slice )
00546         {
00547                 if( slice < 0 )
00548                 {
00549                         throw new IllegalArgumentException( "Negative slices are not allowed!" );
00550                 }
00551 
00552                 List< String > result = new LinkedList< String >();
00553 
00554                 result.add( String.valueOf( slice ) );
00555 
00556                 return result;
00557         }
00558 
00559 }