/* * Copyright (C) 2008 Universidade Federal de Campina Grande * * This file is part of OurGrid. * * OurGrid is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package org.ourgrid.peer.business.controller.allocation; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.ourgrid.common.interfaces.to.RequestSpecification; import org.ourgrid.common.internal.IResponseTO; import org.ourgrid.common.specification.worker.WorkerSpecification; import org.ourgrid.common.statistics.control.AccountingControl; import org.ourgrid.common.util.CommonUtils; import org.ourgrid.peer.business.dao.PeerDAOFactory; import org.ourgrid.peer.to.AllocableWorker; import org.ourgrid.peer.to.Consumer; import org.ourgrid.peer.to.PeerBalance; import org.ourgrid.peer.to.Priority; import org.ourgrid.peer.to.Request; import org.ourgrid.reqtrace.Req; import sun.security.provider.certpath.X509CertPath; import br.edu.ufcg.lsd.commune.network.certification.CertificationUtils; /** * This class provides resources to requests. It attends remote and * local requests. * * This implementation uses ranges of priority in the allocation mechanism. * The request also is in a priority range, so the algorithm tries to respond * using the less priority ranges than request. If are not enough, it tries * the same priority allocations. None greater priority allocation could be used. */ @Req("REQ011") public class DefaultAllocator implements Allocator { private static DefaultAllocator instance = null; private DefaultAllocator() {} public static DefaultAllocator getInstance() { if (instance == null) { instance = new DefaultAllocator(); } return instance; } /* (non-Javadoc) * @see Allocator#getAllocableWorkersForLocalRequest(Request, Collection) */ public List<AllocableWorker> getAllocableWorkersForLocalRequest(List<IResponseTO> responses, X509CertPath myCertPath, Request request, Collection<AllocableWorker> allAllocableWorkers) { Consumer consumer = request.getConsumer(); Map<String, PeerBalance> balances = AccountingControl.getInstance().getBalances( responses, CertificationUtils.getCertSubjectDN(myCertPath)); return getRangeBasedPriorityAllocation(consumer, allAllocableWorkers, request.getSpecification().getRequirements(), Priority.LOCAL_CONSUMER, request.getNeededWorkers(), balances, request.getSpecification().getAnnotations()); } /* (non-Javadoc) * @see Allocator#getAllocableWorkersForRemoteRequest(Consumer, RequestSpec, List) */ public List<AllocableWorker> getAllocableWorkersForRemoteRequest(List<IResponseTO> responses, Consumer consumer, RequestSpecification requestSpecification, String peerDNData, List<AllocableWorker> allocableWorkers) { Priority requestPriority = PeerDAOFactory.getInstance().getTrustCommunitiesDAO().getPriority(responses, consumer.getPublicKey()); Map<String, PeerBalance> balances = AccountingControl.getInstance().getBalances(responses, peerDNData); return getRangeBasedPriorityAllocation(consumer, allocableWorkers, requestSpecification.getRequirements(), requestPriority, requestSpecification.getRequiredWorkers(), balances, requestSpecification.getAnnotations()); } /** * Take the workers beginning from the lower priority ranges, until the request priority. * In the request priority range, workers can be taken according to the network of favors balance. * If two workers consumers has the same priority (or if they belong to the same consumer), * the most recent allocated worker is taken first. * The taken workers must match with the requests requirements. * The result size is lower or equals requestNecessity. * * @param consumerPubKey Consumer public key * @param allocablesByPriority Map with the allocable workers, classified by priority * @param requirements Request requirements, used to match the workers specifications * @param requestPriority The request (consumer) priority * @param requestNecessity The number of workers the request need * @param balances * @return The list of workers to be allocated for this request */ public <A extends AllocableWorker> List<AllocableWorker> getRangeBasedPriorityAllocation(Consumer consumer, Collection<AllocableWorker> allAllocableWorkers, String requirements, Priority requestPriority, int requestNecessity, Map<String, PeerBalance> balances, Map<String, String> jobAnnotations) { Map<Priority, List<AllocableWorker>> allocablesByPriority = createPriorityMap(allAllocableWorkers); int totalAllocableWorkers = getTotalOfAllocables(allocablesByPriority.values()); PriorityProcessor<AllocableWorker> samePriorityProcessor = new SamePriorityProcessor<AllocableWorker>(consumer, requirements, totalAllocableWorkers, balances, jobAnnotations); PriorityProcessor<AllocableWorker> lowerPriorityProcessor = new LowerPriorityProcessor<AllocableWorker>(consumer, requirements, totalAllocableWorkers, balances, jobAnnotations); List<Priority> priorityOrderedList = new ArrayList<Priority>(allocablesByPriority.keySet()); Collections.sort(priorityOrderedList); List<AllocableWorker> workersToAllocate = new LinkedList<AllocableWorker>(); int allocationsLeft = requestNecessity; //sorted from minor to major priority for (Priority currentPriorityRange : priorityOrderedList) { allocationsLeft = requestNecessity - workersToAllocate.size();//update the allocation necessity if((allocationsLeft > 0)) { // FIXME: the priority list need be updated when the workers are donated to local consumers List<AllocableWorker> workersInRange = allocablesByPriority.get(currentPriorityRange); if(requestPriority.compareTo(currentPriorityRange) < 0) { break; } // FIXME: the priority list includes the workers donated to local consumers // this for loop isn't clear, it seemed to sweep throughout all the priorities //taking from the same range and return if( (requestPriority.compareTo(currentPriorityRange) == 0)) { samePriorityProcessor.process(allocationsLeft, workersInRange, workersToAllocate); break; } //Taking allocations from less priority ranges lowerPriorityProcessor.process(allocationsLeft, workersInRange, workersToAllocate); } else { break; } } return workersToAllocate; } private <A extends AllocableWorker> int getTotalOfAllocables(Collection<List<A>> allocables) { /* intern contract */ assert (allocables != null) : "Error in the DefaultAllocator.getRangeBasedPriorityAllocation(), the" + "DefaultAllocator.getTotalOfAllocables() received a null Collection"; int count = 0; for (List<A> list : allocables) { count += list.size(); } return count; } /** * Maps <code>AllocableWorker</code> based in its <code>Priority</code>. * * @param workers Allocable workers to be mapped * @return A map with the priority as key and the worker as value */ private <A extends AllocableWorker> Map<Priority, List<A>> createPriorityMap(Collection<A> workers) { Map<Priority, List<A>> priorityMap = CommonUtils.createSerializableMap(); for (A allocableWorker : workers) { Priority priority = allocableWorker.getPriority(); List<A> sameRangeWorkers = priorityMap.get(priority); if(sameRangeWorkers == null) { sameRangeWorkers = new LinkedList<A>(); priorityMap.put(priority, sameRangeWorkers); } sameRangeWorkers.add(allocableWorker); } return priorityMap; } /* (non-Javadoc) * @see Allocator#getRequestForWorkerSpec(WorkerSpec) */ public Request getRequestForWorkerSpecification(WorkerSpecification remoteWorkerSpecification) { GotWorkerProcessor processor = new GotWorkerProcessor(); List<Request> requests = PeerDAOFactory.getInstance().getRequestDAO().getRunningRequests(); return processor.getInBalanceMatchedRequest(requests, remoteWorkerSpecification); } }