/* * Copyright 2008 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.rioproject.monitor.service.selectors; import com.sun.jini.landlord.LeasedResource; import org.rioproject.monitor.service.InstantiatorResource; import org.rioproject.impl.service.ServiceResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; /** * LeastActiveSelector is used to select a target Cybernode for provisioning. * The strategy used here is to sort the list of all available Cybernodes and * use the one with the least number of active services. * * @author Dennis Reedy */ public class LeastActiveSelector extends ServiceResourceSelector { private final List<Bucket> resourceList = new LinkedList<Bucket>(); static Logger logger = LoggerFactory.getLogger(LeastActiveSelector.class); private LeastActiveComparator comparator = new LeastActiveComparator(); public LeastActiveSelector() { collection = new ArrayList<LeasedResource>(); logger.info("Created LeastActiveSelector"); } /** * Called when resource is selected. * * @param resource The selected ServiceResource */ public void serviceResourceSelected(ServiceResource resource) { InstantiatorResource ir = (InstantiatorResource)resource.getResource(); synchronized(resourceList) { for (Bucket b : resourceList) { if(b.getLabel().equals(ir.getHostAddress())) { List<ServiceResource> list = b.getResources(); for(ServiceResource s : list) { InstantiatorResource i = (InstantiatorResource)s.getResource(); if(i.getInstantiatorUuid().equals(ir.getInstantiatorUuid())) { list.set(list.indexOf(s), s); break; } } break; } } } } @Override protected void add(LeasedResource resource) { ServiceResource sr = (ServiceResource)resource; InstantiatorResource ir = (InstantiatorResource)sr.getResource(); synchronized(resourceList) { Bucket bucket = null; for(Bucket b : resourceList) { if(b.getLabel().equals(ir.getHostAddress())) { bucket = b; break; } } if(bucket==null) { bucket = new Bucket(ir.getHostAddress()); resourceList.add(bucket); } bucket.add(sr); resourceList.set(resourceList.indexOf(bucket), bucket); } super.add(resource); } @Override protected void remove(LeasedResource resource) { ServiceResource sr = (ServiceResource)resource; InstantiatorResource ir = (InstantiatorResource)sr.getResource(); synchronized(resourceList) { for(Bucket b : resourceList) { if(b.getLabel().equals(ir.getHostAddress())) { b.remove(sr); break; } } } super.remove(resource); } @Override public ServiceResource[] getServiceResources() { Bucket[] buckets; synchronized(resourceList) { buckets = resourceList.toArray(new Bucket[resourceList.size()]); } List<ServiceResource> s = new ArrayList<ServiceResource>(); int numIterations = getIterations(); for(int i=0; i<numIterations; i++) { for(Bucket b : buckets) { List<ServiceResource> list = b.getResources(); if(list.size()>i) { s.add(list.get(i)); } } } Collections.sort(s, comparator); ServiceResource[] resources = s.toArray(new ServiceResource[s.size()]); if(logger.isTraceEnabled()) { StringBuilder b = new StringBuilder(); if(resources.length>0) { int i=0; for(ServiceResource sr : resources) { InstantiatorResource ir = (InstantiatorResource)sr.getResource(); if(i>0) { b.append(", "); } int count = ((InstantiatorResource)sr.getResource()).getServiceCount(); b.append("(") .append(ir.getName()) .append(" at ") .append(ir.getHostAddress()) .append(", service count:") .append(count) .append(")"); i++; } } else { b.append("[No registered Cybernodes]"); } logger.trace(b.toString()); } return resources; } /* * Get iteration count */ private int getIterations() { int count = 0; for (Bucket b : resourceList) { count += b.getResources().size(); } int numBuckets; synchronized(resourceList) { numBuckets = resourceList.size(); } if(numBuckets > 1 && count % 2 != 0) count++; return (numBuckets==0?0:count/numBuckets); } /** * Comparator that sorts by the least active first. * The least active is defined as the actual active plus the planned count */ private class LeastActiveComparator implements Comparator<ServiceResource> { public int compare(ServiceResource sr1, ServiceResource sr2) { if (sr1 == sr2) { return 0; } int count1 = 0; int count2 = 0; try { count1 = ((InstantiatorResource)sr1.getResource()).getServiceCount(); count2 = ((InstantiatorResource)sr2.getResource()).getServiceCount(); } catch (Throwable throwable) { logger.warn(throwable.toString(), throwable); } return(count1 - count2); } } /** * A bucket for holding ServiceResources from the same host */ class Bucket { final List<ServiceResource> resources = new ArrayList<ServiceResource>(); final String label; Bucket(String label) { this.label = label; } String getLabel() { return label; } void add(ServiceResource s) { resources.add(s); } void update(ServiceResource s) { int ndx = resources.indexOf(s); if(ndx>=0) resources.set(ndx, s); } void remove(ServiceResource s) { resources.remove(s); } List<ServiceResource> getResources() { return resources; } } }