|
VolD 0.1
|
00001 00002 package de.zib.vold.frontend; 00003 00004 import de.zib.vold.common.VoldException; 00005 import de.zib.vold.common.Key; 00006 import de.zib.vold.volatilelogic.VolatileDirectory; 00007 00008 import java.util.List; 00009 import java.util.Set; 00010 import java.util.Map; 00011 import java.util.HashMap; 00012 00013 import java.util.concurrent.locks.ReentrantReadWriteLock; 00014 00015 import org.slf4j.Logger; 00016 import org.slf4j.LoggerFactory; 00017 00030 public class Frontend 00031 { 00032 private static final Logger log = LoggerFactory.getLogger( Frontend.class ); 00033 private final ReentrantReadWriteLock rwlock; 00034 00035 private VolatileDirectory volatileDirectory; 00036 00037 final String scopeDelimiter = "/"; 00038 00039 // properties 00040 private boolean recursiveScopeLookups; 00041 private boolean prefixLookupsAllowed; 00042 00046 public Frontend( ) 00047 { 00048 this.volatileDirectory = null; 00049 00050 this.rwlock = new ReentrantReadWriteLock( true ); 00051 00052 // properties 00053 setRecursiveScopeLookups( true ); 00054 setPrefixLookupsAllowed( true ); 00055 } 00056 00060 public void setVolatileDirectory( VolatileDirectory volatileDirectory ) 00061 { 00062 this.volatileDirectory = volatileDirectory; 00063 } 00064 00068 public boolean getRecursiveScopeLookups( ) 00069 { 00070 return this.recursiveScopeLookups; 00071 } 00072 00080 public void setRecursiveScopeLookups( boolean recursiveScopeLookups ) 00081 { 00082 this.recursiveScopeLookups = recursiveScopeLookups; 00083 } 00084 00088 public boolean getPrefixLookupsAllowed( ) 00089 { 00090 return this.prefixLookupsAllowed; 00091 } 00092 00099 public void setPrefixLookupsAllowed( boolean prefixLookupsAllowed ) 00100 { 00101 this.prefixLookupsAllowed = prefixLookupsAllowed; 00102 } 00103 00107 protected void checkState( ) 00108 { 00109 if( null == volatileDirectory ) 00110 { 00111 throw new IllegalStateException( "Tried to operate on frontend while it had not been initialized yet. You first need to set a volatile Directory!" ); 00112 } 00113 } 00114 00120 private String prepare_prefix_key( String key ) 00121 { 00122 if( key.length() < 3 ) 00123 return key; 00124 00125 String suffix = key.substring( key.length()-3, key.length() ); 00126 if( suffix.equals( "..." ) ) 00127 { 00128 return key.substring( 0, key.length()-3 ); 00129 } 00130 else 00131 { 00132 return key; 00133 } 00134 } 00135 00145 public void insert( String source, Key key, Set<String> value ) 00146 { 00147 // guard 00148 { 00149 log.trace( "Insert: from source " + source + ": " + key._buildkey().toString() + " |--> " + value.toString() ); 00150 00151 checkState(); 00152 } 00153 00154 try 00155 { 00156 rwlock.writeLock().lock(); 00157 00158 List< String > _key = key._buildkey(); 00159 _key.add( source ); 00160 00161 volatileDirectory.insert( _key, value ); 00162 } 00163 finally 00164 { 00165 rwlock.writeLock().unlock(); 00166 } 00167 } 00168 00175 public void refresh( String source, Key key ) 00176 { 00177 // guard 00178 { 00179 log.trace( "Refresh: from source " + source + ": " + key._buildkey().toString() ); 00180 00181 checkState(); 00182 } 00183 00184 try 00185 { 00186 rwlock.writeLock().lock(); 00187 00188 List< String > _key = key._buildkey(); 00189 _key.add( source ); 00190 00191 volatileDirectory.refresh( _key ); 00192 } 00193 finally 00194 { 00195 rwlock.writeLock().unlock(); 00196 } 00197 } 00198 00205 public void delete( String source, Key key ) 00206 { 00207 // guard 00208 { 00209 log.trace( "Delete: from source " + source + ": " + key._buildkey().toString() ); 00210 00211 checkState(); 00212 } 00213 00214 try 00215 { 00216 rwlock.writeLock().lock(); 00217 00218 List< String > _key = key._buildkey(); 00219 _key.add( source ); 00220 00221 volatileDirectory.delete( _key ); 00222 } 00223 finally 00224 { 00225 rwlock.writeLock().unlock(); 00226 } 00227 } 00228 00238 public Map< Key, Set< String > > lookup( Key key ) 00239 { 00240 VoldException found_exception = null; 00241 00242 // guard 00243 { 00244 log.trace( "Lookup: " + key.toString() ); 00245 00246 checkState(); 00247 } 00248 00249 try 00250 { 00251 rwlock.readLock().lock(); 00252 00253 if( getRecursiveScopeLookups() ) 00254 { 00255 String scope = key.get_scope(); 00256 Map< Key, Set< String > > result; 00257 00258 while( true ) 00259 { 00260 try 00261 { 00262 result = scopeLookup( new Key( scope, key.get_type(), key.get_keyname() ) ); 00263 } 00264 catch( VoldException e ) 00265 { 00266 log.error( "Error in recursive lookup for key " + key._buildkey().toString() + " (actual scope: " + scope + ") - simply skipping: " + e.getMessage() ); 00267 found_exception = e; 00268 continue; 00269 } 00270 00271 if( 0 != result.size() ) 00272 { 00273 return result; 00274 } 00275 00276 scope = scope_base( scope ); 00277 00278 if( null == scope ) 00279 { 00280 if( null != found_exception ) 00281 throw found_exception; 00282 00283 return new HashMap< Key, Set< String > >(); 00284 } 00285 } 00286 } 00287 else 00288 { 00289 return scopeLookup( key ); 00290 } 00291 } 00292 finally 00293 { 00294 rwlock.readLock().unlock(); 00295 } 00296 } 00297 00304 private String scope_base( String scope ) 00305 { 00306 int lastdelim = scope.lastIndexOf( scopeDelimiter, scope.length()-2 ); 00307 00308 if( lastdelim < 0 ) 00309 return null; 00310 00311 return scope.substring( 0, lastdelim+1 ); 00312 } 00313 00323 private Map< Key, Set< String > > scopeLookup( Key key ) 00324 { 00325 if( null == key ) 00326 { 00327 throw new IllegalArgumentException( "null is not allowed as key in Frontend.scopeLookup( key )!" ); 00328 } 00329 00330 Map< List< String >, Set< String > > _result; // results from backend 00331 Map< Key, Set< String > > result = new HashMap< Key, Set< String > >(); // transformed results 00332 00333 // get results from directory 00334 { 00335 String preparedkey = prepare_prefix_key( key.get_keyname() ); 00336 00337 if( getPrefixLookupsAllowed() && preparedkey.length() != key.get_keyname().length() ) 00338 { 00339 key = new Key( key.get_scope(), key.get_type(), preparedkey ); 00340 00341 try 00342 { 00343 _result = volatileDirectory.prefixLookup( key._buildkey() ); 00344 } 00345 catch( VoldException e ) 00346 { 00347 throw new VoldException( "In Frontend.scopeLookup( " + key._buildkey().toString() + "): ", e ); 00348 } 00349 } 00350 else 00351 { 00352 List< String > _key = key._buildkey(); 00353 00354 // add another empty directory to just make a prefix lookup for 00355 // this key but different hosts 00356 _key.add( new String() ); 00357 00358 try 00359 { 00360 _result = volatileDirectory.prefixLookup( _key ); 00361 } 00362 catch( VoldException e ) 00363 { 00364 throw new VoldException( "In Frontend.scopeLookup( " + _key.toString() + "): ", e ); 00365 } 00366 } 00367 } 00368 00369 // merge keys with the same host 00370 { 00371 for( Map.Entry< List< String >, Set< String > > entry: _result.entrySet() ) 00372 { 00373 Key k; 00374 try 00375 { 00376 k = Key.buildkey( entry.getKey() ); 00377 } 00378 catch( IllegalArgumentException e ) 00379 { 00380 log.error( "Internal Error: simply skipping invalid key in backend: " + entry.getKey().toString() ); 00381 continue; 00382 } 00383 00384 // merge already existing entries -> same hosts 00385 if( result.containsKey( k ) ) 00386 { 00387 Set< String > l = result.get( k ); 00388 00389 l.addAll( entry.getValue() ); 00390 } 00391 else 00392 { 00393 result.put( k, entry.getValue() ); 00394 } 00395 } 00396 } 00397 00398 return result; 00399 } 00400 }