xbird.xquery.ext.grid.DispatchQueryExecTask.java Source code

Java tutorial

Introduction

Here is the source code for xbird.xquery.ext.grid.DispatchQueryExecTask.java

Source

/*
 * @(#)$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);
    }

}