001: /**
002: * This file or a portion of this file is licensed under the terms of
003: * the Globus Toolkit Public License, found in file GTPL, or at
004: * http://www.globus.org/toolkit/download/license.html. This notice must
005: * appear in redistributions of this file, with or without modification.
006: *
007: * Redistributions of this Software, with or without modification, must
008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
009: * some other similar material which is provided with the Software (if
010: * any).
011: *
012: * Copyright 1999-2004 University of Chicago and The University of
013: * Southern California. All rights reserved.
014: */package org.griphyn.cPlanner.selector.replica;
015:
016: import org.griphyn.cPlanner.common.LogManager;
017: import org.griphyn.cPlanner.common.PegasusProperties;
018: import org.griphyn.cPlanner.common.PegRandom;
019:
020: import org.griphyn.cPlanner.classes.ReplicaLocation;
021:
022: import org.griphyn.common.catalog.ReplicaCatalogEntry;
023:
024: import java.util.ArrayList;
025: import java.util.Iterator;
026: import java.util.Vector;
027: import java.util.Map;
028: import java.util.HashMap;
029: import java.util.LinkedHashSet;
030: import java.util.Set;
031: import java.util.StringTokenizer;
032:
033: /**
034: * A replica selector, that allows the user to specify good sites and bad sites
035: * for staging in data to a compute site.
036: *
037: * <p>
038: * A good site for a compute site X, is a preferred site from which replicas
039: * should be staged to site X. If there are more than one good sites having a
040: * particular replica, then a random siteis selected amongst these preferred sites.
041: * <p>
042: * A bad site for a compute site X, is a site from which replica's should not be
043: * staged. The reason of not accessing replica from a bad site can vary from
044: * the link being down, to the user not having permissions on that site's data.
045: * <p>
046: * The good | bad sites are specified by the properties
047: * pegasus.selector.replica.*.prefer.stagein.sites| pegasus.selector.replica.*.ignore.stagein.sites, where
048: * the * in the property name denotes the name of the compute site.
049: * A * in the property key is taken to mean all sites.
050: *<p>
051: * The pegasus.selector.replica.*.prefer.stagein.sites property takes precedence over
052: * pegasus.selector.replica.*.ignore.stagein.sites property i.e. if for a site X, a site Y is
053: * specified both in the ignored and the preferred set, then site Y is taken to
054: * mean as only a preferred site for a site X.
055: *
056: * <p>
057: * In order to use the replica selector implemented by this class,
058: * <pre>
059: * - the property pegasus.selector.replica.selector must be set to value Restricted.
060: * </pre>
061: *
062: * @author Karan Vahi
063: * @author Gaurang Mehta
064: *
065: * @version $Revision: 50 $
066: */
067: public class Restricted extends Default {
068:
069: /**
070: * A short description of the replica selector.
071: */
072: private static final String mDescription = "Restricted";
073:
074: /**
075: * The property prefix for all properties used by this selector.
076: */
077: private static final String PROPERTY_PREFIX = "pegasus.selector.replica";
078:
079: /**
080: * The property suffix for determining the preferred sites for a site x.
081: */
082: private static final String PROPERTY_PREFER_SUFFIX = "prefer.stagein.sites";
083:
084: /**
085: * The property suffix for determining the ignored sites for a site x.
086: */
087: private static final String PROPERTY_IGNORE_SUFFIX = "ignore.stagein.sites";
088:
089: /**
090: * A Map indexed by site handles, that contains a set of site handles.
091: * The sites in the set are the sites from which to prefer data transfers to
092: * the site referred to by key of the map.
093: */
094: private Map mPreferredSitesMap;
095:
096: /**
097: * The set of preferred sites, that are preferred stagein sites for all sites.
098: * Referred to by "pegasus.selector.replica.*.prefer.sites" property.
099: */
100: private Set mGlobalPreferredSites;
101:
102: /**
103: * A Map indexed by site handles, that contains a set of site handles.
104: * The sites in the set are the sites from which to ignore data transfers to
105: * the site referred to by key of the map.
106: */
107: private Map mIgnoredSitesMap;
108:
109: /**
110: * The Set of ignored sites, that are ignored for selecting replicas for all
111: * sites. Referred to by "pegasus.selector.replica.*.default.sites" property.
112: */
113: private Set mGlobalIgnoredSites;
114:
115: /**
116: * The overloaded constructor, that is called by load method.
117: *
118: * @param properties the <code>PegasusProperties</code> object containing all
119: * the properties required by Pegasus.
120: */
121: public Restricted(PegasusProperties properties) {
122: super (properties);
123: mIgnoredSitesMap = new HashMap(15);
124: mPreferredSitesMap = new HashMap(15);
125: mGlobalIgnoredSites = getSitesSet(mProps.getAllIgnoredSites());
126: mGlobalPreferredSites = getSitesSet(mProps
127: .getAllPreferredSites());
128: }
129:
130: /**
131: * This chooses a location amongst all the locations returned by the replica
132: * location service. If a location is found with re attribute same as the
133: * preference pool, it is taken. Else a random location is selected and
134: * returned. If more than one location for the lfn is found at the preference
135: * pool, then also a random location amongst the ones at the preference pool
136: * is selected.
137: *
138: * @param rl the <code>ReplicaLocation</code> object containing all
139: * the pfn's associated with that LFN.
140: * @param preferredSite the preffered site for picking up the replicas.
141: *
142: * @return <code>ReplicaCatalogEntry</code> corresponding to the location selected.
143: *
144: * @see org.griphyn.cPlanner.classes.ReplicaLocation
145: */
146: public ReplicaCatalogEntry selectReplica(ReplicaLocation rl,
147: String preferredSite) {
148:
149: // public ReplicaLocation select( String lfn,
150: // Vector locations,
151: // String preferredSite ) {
152:
153: String lfn = rl.getLFN();
154: String site;
155: ArrayList prefLocs = new ArrayList();
156: int locSelected;
157:
158: //build state on the basis of preferred sites
159: populateSiteMaps(preferredSite);
160:
161: mLogger.log(
162: "[RestrictedReplicaSelector] Selecting a pfn for lfn "
163: + lfn + "\n amongst" + rl,
164: LogManager.DEBUG_MESSAGE_LEVEL);
165:
166: ReplicaCatalogEntry rce;
167: for (Iterator it = rl.pfnIterator(); it.hasNext();) {
168: rce = (ReplicaCatalogEntry) it.next();
169: site = rce.getResourceHandle();
170:
171: //check if equal to the execution site
172: //or site is preferred to stage to execution site.
173: if (prefer(site, preferredSite)) {
174:
175: prefLocs.add(rce);
176:
177: //return the one with file url for ligo stuff
178: //is temporary till new api coded
179: if (rce.getPFN().startsWith(FILE_URL_SCHEME)) {
180: //this is the one which is reqd for ligo
181: //return the location instead of breaking
182: return rce;
183: }
184: }
185:
186: //remove a URL if it is a file URL not associated
187: //with compute site or a URL with a site that is
188: //to be ignored for staging data to any site.
189: else if (rce.getPFN().startsWith(FILE_URL_SCHEME)
190: || ignore(site, preferredSite)) {
191: it.remove();
192: }
193:
194: }
195:
196: int noOfLocs = rl.getPFNCount();
197: if (noOfLocs == 0) {
198: //in all likelihood all the urls were file urls and
199: //none were associated with the preference pool.
200: //replica not selected
201: throw new RuntimeException(
202: "Unable to select any location from "
203: + "the list passed for lfn " + lfn);
204: }
205:
206: if (prefLocs.isEmpty()) {
207: //select a random location from all the matching locations
208: locSelected = PegRandom.getInteger(noOfLocs - 1);
209: rce = rl.getPFN(locSelected);
210:
211: } else {
212: //select a random location amongst all the preferred locations
213: int preferredSize = prefLocs.size();
214: locSelected = PegRandom.getInteger(preferredSize - 1);
215: rce = (ReplicaCatalogEntry) prefLocs.get(locSelected);
216:
217: //create symbolic links instead of going through gridftp server
218: if (mUseSymLinks) {
219: rce = replaceProtocolFromURL(rce);
220: }
221: }
222:
223: return rce;
224:
225: }
226:
227: /**
228: * Returns a short description of the replica selector.
229: *
230: * @return string corresponding to the description.
231: */
232: public String description() {
233: return mDescription;
234: }
235:
236: /**
237: * Returns a boolean indicating whether a source site is to be preffered for
238: * staging to a destination site
239: *
240: * @param source the source site.
241: * @param destination the destination site.
242: *
243: * @return true if source is a preferred site for staging to destination,
244: * else false.
245: */
246: protected boolean prefer(String source, String destination) {
247: boolean result = false;
248: Set s;
249: if (mPreferredSitesMap.containsKey(destination)) {
250: s = (Set) mPreferredSitesMap.get(destination);
251: result = s.contains(source);
252: }
253:
254: if (!result) {
255: //check for source in global preferred sites
256: result = globallyPreferred(source);
257: }
258: return result;
259: }
260:
261: /**
262: * Returns a boolean indicating whether a source site is to be ignored for
263: * staging to a destination site
264: *
265: * @param source the source site.
266: * @param destination the destination site.
267: *
268: * @return true if source is tp be ignored while staging to destination,
269: * else false.
270: */
271: protected boolean ignore(String source, String destination) {
272: boolean result = false;
273: Set s;
274: if (mIgnoredSitesMap.containsKey(destination)) {
275: s = (Set) mIgnoredSitesMap.get(destination);
276: result = s.contains(source);
277: }
278:
279: if (!result) {
280: //check for source in global preferred sites
281: result = globallyIgnored(source);
282: }
283: return result;
284: }
285:
286: /**
287: * Returns a boolean indicating whether a site is a preferred replica source
288: * for all compute sites.
289: *
290: * @param site the site to test for.
291: *
292: * @return boolean.
293: */
294: protected boolean globallyPreferred(String site) {
295: return mGlobalPreferredSites.contains(site);
296: }
297:
298: /**
299: * Returns a boolean indicating whether a site is to be ignored as a replica
300: * source for all compute sites.
301: *
302: * @param site the site to test for.
303: *
304: * @return boolean.
305: */
306: protected boolean globallyIgnored(String site) {
307: return mGlobalIgnoredSites.contains(site);
308: }
309:
310: /**
311: * Returns the name of the property, for a particular site X. The value of
312: * the property contains a comma separated list of site handles that are
313: * to be ignored|preferred while selecting replicas to stage to the site X.
314: *
315: * @param site the site X.
316: * @param suffix the property suffix to be applied.
317: *
318: * @return the name of the property.
319: */
320: protected String getProperty(String site, String suffix) {
321: StringBuffer sb = new StringBuffer();
322: sb.append(this .PROPERTY_PREFIX).append('.').append(site)
323: .append('.').append(suffix);
324: return sb.toString();
325: }
326:
327: /**
328: * Builds up the set of preferred and ignored sites for a site.
329: *
330: * @param site the site for which to identify the preferred and ignored
331: * sites.
332: *
333: */
334: private void populateSiteMaps(String site) {
335: //check to see if we already have an entry
336: if (mPreferredSitesMap.containsKey(site)) {
337: //we already have computed the site
338: return;
339: }
340:
341: //build up preferred sites for site
342: String name = getProperty(site, this .PROPERTY_PREFER_SUFFIX);
343: Set p = this .getSitesSet(mProps.getProperty(name));
344: mPreferredSitesMap.put(site, p);
345:
346: //build up ignored sites for site
347: name = getProperty(site, this .PROPERTY_IGNORE_SUFFIX);
348: Set i = this .getSitesSet(mProps.getProperty(name));
349: mIgnoredSitesMap.put(site, i);
350:
351: }
352:
353: /**
354: * Returns a set of third party sites. An empty set is returned if value is
355: * null.
356: *
357: * @param value the comma separated list in the properties file.
358: *
359: * @return Set containing the names of the pools.
360: */
361: private Set getSitesSet(String value) {
362: Set set = new LinkedHashSet();
363: String site;
364: if (value == null || value.length() == 0) {
365: return set;
366: }
367:
368: for (StringTokenizer st = new StringTokenizer(value, ","); st
369: .hasMoreTokens();) {
370: site = (String) st.nextToken();
371: set.add(site);
372: }
373: return set;
374: }
375:
376: }
|