|
VolD 0.1
|
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 }