Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package brooklyn.location.jclouds.pool;
  
  import static brooklyn.location.jclouds.pool.MachinePoolPredicates.compose;
  import static brooklyn.location.jclouds.pool.MachinePoolPredicates.matching;
  
  import java.util.List;
  import java.util.Set;
 
 
Contains details of machines detected at a given cloud (ComputeService), and records claims made against those machines via this pool.

Machine instances themselves are persisted and rescanned as new instances of this class are created. Claims however are specific to this instance of the class, i.e. not persisted.

This class is believed to be thread-safe. Refreshes to the remote detected machines are synchronized on the pool instance. Details of detected and claimed machines are also synchronized on the pool instance. (If it is necessary to claim machines whilst the pool is being rescanned, we can investigate a more sophisticated threading model. Access to some fields is clearly independent and uses a tighter synchonization strategy, e.g. templates. Synchronization of fields within a synch block on the class instance is permitted, but not the other way round, and synching on multiple fields is also not permitted.)

Callers wishing to guarantee results of e.g. ensureUnclaimed remaining available can synchronize on this class for the duration that they wish to have that guarantee (at the cost, of course, of any other threads being able to access this pool).

If underlying provisioning/destroying operations fail, the pool currently may be in an unknown state, currently. If more robustness is needed this can be added.

 
 public class MachinePool {
     
     private static final Logger log = LoggerFactory.getLogger(MachinePool.class);
     
     protected final ComputeService computeService;
     final AtomicBoolean refreshNeeded = new AtomicBoolean(true);
     String poolName = null;
    
    
all machines detected, less those in the black list
 
     volatile MachineSet detectedMachines = new MachineSet();
     volatile MachineSet matchedMachines = new MachineSet();
     volatile MachineSet claimedMachines = new MachineSet();
     volatile MachineSet blacklistedMachines = new MachineSet();
     
     public MachinePool(ComputeService computeService) {
         this. = computeService;
     }
     
     protected synchronized void init() {
         if (!.get()) return;
         refresh();
     }
     
     public void setPoolName(String poolName) {
         if (poolName!=null)
             .warn("Changing pool name of "+this+" (from "+this.+" to "+poolName+") is discouraged.");
         this. = poolName;
     }
    
pool name is used as a group/label by jclouds, for convenience only; it has no special properties for detecting matching instances (use explicit tags on the templates, for that). defaults to name of pool class and user name. callers should set pool name before getting, if using a custom name.
 
     public synchronized String getPoolName() {
         if (==null)
              = getClass().getSimpleName()+"-"+System.getProperty("user.name");
         return ;
     }
    
    
refreshes the pool of machines from the server (finding all instances matching the registered templates)
 
     public synchronized void refresh() {
         .set(false);
         Set<? extends ComputeMetadatacomputes = .listNodes();
         Set<NodeMetadatanodes = new LinkedHashSet<NodeMetadata>();
         for (ComputeMetadata ccomputes) {
             if (c instanceof NodeMetadata) {
                 nodes.add((NodeMetadata)c);
             } else {
                // TODO should we try to fetch more info?
                .warn("MachinePool "+this+" ignoring non-Node record for remote machine: "+c);
            }
        }
        MachineSet allNewDetectedMachines = new MachineSet(nodes);
        MachineSet newDetectedMachines = filterForAllowedMachines(allNewDetectedMachines);
        MachineSet oldDetectedMachines = ;
        MachineSet newMatchedMachines = new MachineSet();
         = newDetectedMachines;
        MachineSet appearedMachinesIncludingBlacklist = allNewDetectedMachines.removed(oldDetectedMachines);
        MachineSet appearedMachines = filterForAllowedMachines(appearedMachinesIncludingBlacklist);
        if (appearedMachinesIncludingBlacklist.size()>appearedMachines.size())
            if (.isDebugEnabled()) .debug("Pool "+this+", ignoring "+(appearedMachinesIncludingBlacklist.size()-appearedMachines.size())+" disallowed");
        int matchedAppeared = 0;
        for (NodeMetadata mappearedMachines) {
            if (m.getStatus() != ..) {
                if (.isDebugEnabled()) 
                    .debug("Pool "+this+", newly detected machine "+m+", not running ("+m.getStatus()+")");
            } else {
                Set<ReusableMachineTemplatets = getTemplatesMatchingInstance(m);
                if (!ts.isEmpty()) {
                    matchedAppeared++;
                    newMatchedMachines = newMatchedMachines.added(new MachineSet(m));
                    if (.isDebugEnabled()) 
                        .debug("Pool "+this+", newly detected machine "+m+", matches pool templates "+ts);
                } else {
                    if (.isDebugEnabled()) 
                        .debug("Pool "+this+", newly detected machine "+m+", does not match any pool templates");
                }
            }
        }
        if (matchedAppeared>0) {
            .info("Pool "+this+" discovered "+matchedAppeared+" matching machines (of "+appearedMachines.size()+" total new; "+newDetectedMachines.size()+" total including claimed and unmatched)");
        } else {
            if (.isDebugEnabled()) 
                .debug("Pool "+this+" discovered "+matchedAppeared+" matching machines (of "+appearedMachines.size()+" total new; "+newDetectedMachines.size()+" total including claimed and unmatched)");
        }
         = newMatchedMachines;
    }
    protected MachineSet filterForAllowedMachines(MachineSet input) {
        return input.removed();
    }
    // TODO template registry and claiming from a template could be a separate responsibility
    
        registerTemplates(template);
        return template;
    }
    protected void registerTemplates(ReusableMachineTemplate ...templatesToReg) {
        synchronized () { 
            for (ReusableMachineTemplate templatetemplatesToReg)
                .add(template); 
        }
    }
    
    protected ReusableMachineTemplate newTemplate(String name) {
        return registerTemplate(new ReusableMachineTemplate(name));
    }
    
        List<ReusableMachineTemplateresult;
        synchronized () { result = ImmutableList.copyOf(); }
        return result;
    }
    
    
all machines matching any templates
    public MachineSet all() {
        init();
        return ;
    }

    
machines matching any templates which have not been claimed
    public MachineSet unclaimed() {
        init();
        synchronized (this) {
            return .removed();
        }
    }
    
    
returns all machines matching the given criteria (may be claimed)
    @SuppressWarnings("unchecked")
    public MachineSet all(Predicate<NodeMetadatacriterion) {
        // To avoid generics complaints in callers caused by varargs, overload here
        return all(new Predicate[] {criterion});
    }
    
    
returns all machines matching the given criteria (may be claimed)
    public MachineSet all(Predicate<NodeMetadata> ...ops) {
        return new MachineSet(Iterables.filter(all(), compose(ops)));
    }

    
returns unclaimed machines matching the given criteria
    @SuppressWarnings("unchecked")
    public MachineSet unclaimed(Predicate<NodeMetadatacriterion) {
        // To avoid generics complaints in callers caused by varargs, overload here
        return unclaimed(new Predicate[] {criterion});
    }
    
    
returns unclaimed machines matching the given criteria
    public MachineSet unclaimed(Predicate<NodeMetadata> ...criteria) {
        return new MachineSet(Iterables.filter(unclaimed(), compose(criteria)));
    }

    
creates machines if necessary so that this spec exists (may already be claimed however) returns a set of all matching machines, guaranteed non-empty (but possibly some are already claimed)
    public MachineSet ensureExists(ReusableMachineTemplate template) {
        return ensureExists(1, template);
    }
    public synchronized void addToBlacklist(MachineSet newToBlacklist) {
        setBlacklist(.added(newToBlacklist));
    }
    
    
replaces the blacklist set; callers should generally perform a refresh() afterwards, to trigger re-detection of blacklisted machines
    public synchronized void setBlacklist(MachineSet newBlacklist) {
         = newBlacklist;
    }
    
    
creates machines if necessary so that this spec exists (may already be claimed however); returns a set of all matching machines, of size at least count (but possibly some are already claimed). (the pool can change at any point, so this set is a best-effort but may be out of date. see javadoc comments on this class.)
    public MachineSet ensureExists(int countReusableMachineTemplate template) {
        MachineSet current;
        current = all(matching(template));
        if (current.size() >= count)
            return current;
        //have to create more
        MachineSet moreNeeded = create(count-current.size(), template);
        return current.added(moreNeeded);
    }
    
    
creates machines if necessary so that this spec can subsequently be claimed; returns all such unclaimed machines, guaranteed to be non-empty. (the pool can change at any point, so this set is a best-effort but may be out of date. see javadoc comments on this class.)
        return ensureUnclaimed(1, template);
    }

    
creates machines if necessary so that this spec can subsequently be claimed; returns a set of at least count unclaimed machines
    public MachineSet ensureUnclaimed(int countReusableMachineTemplate template) {
        MachineSet current;
        current = unclaimed(matching(template));
        if (current.size() >= count)
            return current;
        //have to create more
        MachineSet moreNeeded = create(count-current.size(), template);
        return current.added(moreNeeded);
    }
        for (ReusableMachineTemplate tgetTemplates()) {
            if (matching(t).apply(nm)) {
               result.add(t); 
            }
        }        
        return result;
    }
    
    
creates the given number of machines of the indicated template
    public MachineSet create(int countReusableMachineTemplate template) {
        Set<? extends NodeMetadatanodes;
        try {
            Template t = template.newJcloudsTemplate();
            if (.isDebugEnabled()) .debug("Creating "+count+" new instances of "+t);
            nodes = .createNodesInGroup(getPoolName(), countt);
        } catch (RunNodesException e) {
            throw Throwables.propagate(e);
        }
        MachineSet result = new MachineSet(nodes);
        registerNewNodes(resulttemplate);
        return result;
    }
    protected void registerNewNodes(MachineSet resultReusableMachineTemplate template) {
        for (NodeMetadata mresult) {
            Set<ReusableMachineTemplatets = getTemplatesMatchingInstance(m);
            if (ts.isEmpty()) {
                .error("Pool "+this+", created machine "+m+" from template "+template+", but no pool templates match!");
            } else {
                if (.isDebugEnabled())
                    .debug("Pool "+this+", created machine "+m+" from template "+template+", matching templates "+ts);
            }
        }
        synchronized (this) {
             = .added(result);
             = .added(result);
        }
    }

    
claims the indicated number of machines with the indicated spec, creating if necessary
    public MachineSet claim(int countReusableMachineTemplate t) {
        init();
        Set<NodeMetadataclaiming = new LinkedHashSet<NodeMetadata>();
        while (claiming.size() < count) {
            MachineSet mm = ensureUnclaimed(count - claiming.size(), t);
            for (NodeMetadata m : mm) {
                synchronized (this) {
                    if (claiming.size() < count && !.contains(m)) {
                        claiming.add(m);
                         = .added(new MachineSet(m));
                    }
                }
            }
        }
        MachineSet result = new MachineSet(claiming);
        return result;
    }


    
claims the indicated set of machines; throws exception if cannot all be claimed; returns the set passed in if successful
    public MachineSet claim(MachineSet set) {
        init();
        synchronized (this) {
            MachineSet originalClaimed = ;
             = .added(set);
            MachineSet newlyClaimed = .removed(originalClaimed);
            if (newlyClaimed.size() != set.size()) {
                //did not claim all; unclaim and fail
                 = originalClaimed;
                MachineSet unavailable = set.removed(newlyClaimed); 
                throw new IllegalArgumentException("Could not claim all requested machines; failed to claim "+unavailable);
            }
            return newlyClaimed;
        }
    }
    
    public int unclaim(MachineSet set) {
        init();
        synchronized (this) {
            MachineSet originalClaimed = ;
             = .removed(set);
            return originalClaimed.size() - .size();
        }
    }
    
    public int destroy(final MachineSet set) {
        init();
        synchronized (this) {
             = .removed(set);
             = .removed(set);
             = .removed(set);
        }
        Set<? extends NodeMetadatadestroyed = .destroyNodesMatching(new Predicate<NodeMetadata>() {
            @Override
            public boolean apply(NodeMetadata input) {
                return set.contains(input);
            }
        });
        synchronized (this) {
            //in case a rescan happened while we were destroying
             = .removed(set);
             = .removed(set);
             = .removed(set);
        }
        return destroyed.size();        
    }
        
    
New to GrepCode? Check out our FAQ X