Java tutorial
/* * @(#)$Id$ * * Copyright 2006-2008 Makoto YUI * * 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. * * Contributors: * Makoto YUI - initial implementation */ package xbird.xquery.ext.grid; import java.util.ArrayList; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import gridool.GridConfiguration; import gridool.GridException; import gridool.GridJob; import gridool.GridKernel; import gridool.GridNode; import gridool.GridTask; import gridool.annotation.DirectoryResource; import gridool.annotation.GridConfigResource; import gridool.annotation.GridKernelResource; import gridool.communication.payload.GridNodeInfo; import gridool.construct.GridTaskAdapter; import gridool.directory.LocalDirectory; import gridool.locking.LockManager; import gridool.routing.GridNodeSelector; import gridool.routing.GridTaskRouter; import gridool.util.GridUtils; import xbird.storage.DbException; import xbird.util.struct.Pair; import xbird.xquery.dm.value.Item; import xbird.xquery.dm.value.Sequence; import xbird.xquery.expr.XQExpression; import xbird.xquery.expr.var.BindingVariable; /** * * <DIV lang="en"></DIV> * <DIV lang="ja"></DIV> * * @author Makoto YUI (yuin405+xbird@gmail.com) */ public final class DispatchQueryExecTask extends GridTaskAdapter { private static final long serialVersionUID = 5561645251880268369L; private static final Log LOG = LogFactory.getLog(DispatchQueryExecTask.class); private final BindingVariable bindingVar; private final XQExpression bodyExpr; private final List<String> relativePaths; private final List<GridNode> excludeNodeList; private final boolean redirectable; // ---------------------------------------- // injected resources @GridKernelResource private transient GridKernel grid; @GridConfigResource private transient GridConfiguration config; @DirectoryResource private transient LocalDirectory directory; // ---------------------------------------- @SuppressWarnings("unchecked") public DispatchQueryExecTask(GridJob job, BindingVariable bindingVar, XQExpression bodyExpr, List<String> relativePaths, boolean redirectable) { super(job, true); assert (bindingVar != null); assert (bodyExpr != null); assert (relativePaths != null); this.bindingVar = bindingVar; this.bodyExpr = bodyExpr; this.relativePaths = relativePaths; this.excludeNodeList = new ArrayList<GridNode>(2); this.redirectable = redirectable; } @Override public boolean isAsyncTask() { return false; } @Override public boolean injectResources() { return true; } public boolean isRedirectable() { return redirectable; } public BindingVariable getBindingVariable() { return bindingVar; } public XQExpression getBodyExpression() { return bodyExpr; } public List<String> getRelativePaths() { return relativePaths; } @Override public Sequence<? extends Item> execute() throws GridException { final Future<Sequence<? extends Item>> future = grid.execute(QueryExecJob.class, this); try { return future.get(); } catch (InterruptedException ie) { LOG.error(ie.getMessage()); throw new GridException(ie.getMessage(), ie); } catch (ExecutionException ee) { LOG.error(ee.getMessage()); throw new GridException(ee.getMessage(), ee); } } /** * @see QueryExecJob#map(gridool.routing.GridTaskRouter, DispatchQueryExecTask) */ public Map<GridTask, GridNode> mapQueryTask(QueryExecJob execJob) throws GridException { checkInjectedResources(); final GridNodeInfo localNode = GridUtils.getLocalNode(config); if (!excludeNodeList.contains(localNode)) { excludeNodeList.add(localNode); } final GridNodeSelector nodeSelector = config.getNodeSelector(); final LockManager lockManager = directory.getLockManager(); final Map<GridNode, List<String>> assignMap = new HashMap<GridNode, List<String>>(relativePaths.size()); final List<Pair<String, Lock>> localExecResources = new ArrayList<Pair<String, Lock>>(relativePaths.size()); int totalLocked = 0; for (String path : relativePaths) { ReadWriteLock lock = lockManager.obtainLock(path); final Lock rlock = lock.readLock(); if (rlock.tryLock()) { localExecResources.add(new Pair<String, Lock>(path, rlock)); } else { totalLocked++; final List<GridNode> replicatedNodes; try { replicatedNodes = directory.exactSearch(path, excludeNodeList); } catch (DbException e) { LOG.error(e.getMessage()); throw new GridException("Exception caused while lookup: " + path, e); } if (replicatedNodes == null || replicatedNodes.isEmpty()) { throw new GridException("No replicated document found for path: " + path); } // TODO Select a node that least recently used for write requests. GridNode node = nodeSelector.selectNode(replicatedNodes, this, config); assert (node != null); List<String> mappedPaths = assignMap.get(node); if (mappedPaths == null) { mappedPaths = new ArrayList<String>(16); assignMap.put(node, mappedPaths); } mappedPaths.add(path); } } final Map<GridTask, GridNode> map = new IdentityHashMap<GridTask, GridNode>(assignMap.size() + 1); for (Map.Entry<GridNode, List<String>> e : assignMap.entrySet()) { GridNode node = e.getKey(); List<String> mappedPaths = e.getValue(); DispatchQueryExecTask dispatchTask = new DispatchQueryExecTask(execJob, bindingVar, bodyExpr, mappedPaths, true); map.put(dispatchTask, node); } if (!localExecResources.isEmpty()) { boolean doForwarding = redirectable; LocalQueryExecTask localTask = new LocalQueryExecTask(execJob, bindingVar, bodyExpr, localExecResources, doForwarding); map.put(localTask, localNode); } if (LOG.isInfoEnabled()) { LOG.info("DispatchQueryExecTask is mapped to " + assignMap.size() + " DispatchQueryExecTask and " + (localExecResources.isEmpty() ? '0' : '1') + " LocalQueryExecTask (" + localExecResources.size() + " localExecResources), " + totalLocked + " documents are write-locked"); } return map; } private void checkInjectedResources() { if (config == null) { throw new IllegalStateException("GridConfiguration is not injected"); } if (directory == null) { throw new IllegalStateException("LocalDirectory is not injected"); } } @Override public List<GridNode> listFailoverCandidates(GridTask task, GridTaskRouter router) { GridNode[] liveNodes = router.getAllNodes(); return GridUtils.selectSuperNodes(liveNodes); } }