Package xbird.xquery.ext.grid

Source Code of xbird.xquery.ext.grid.DispatchQueryExecTask

/*
* @(#)$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 gridool.GridConfiguration;
import gridool.GridException;
import gridool.GridJob;
import gridool.GridKernel;
import gridool.GridNode;
import gridool.GridTask;
import gridool.annotation.GridConfigResource;
import gridool.annotation.GridDirectoryResource;
import gridool.annotation.GridKernelResource;
import gridool.communication.payload.GridNodeInfo;
import gridool.construct.GridTaskAdapter;
import gridool.directory.ILocalDirectory;
import gridool.directory.helpers.GridNodeValueCollector;
import gridool.locking.LockManager;
import gridool.routing.GridNodeSelector;
import gridool.routing.GridTaskRouter;
import gridool.util.GridUtils;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
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 javax.annotation.CheckForNull;
import javax.annotation.Nonnull;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import xbird.storage.DbException;
import xbird.util.io.FastByteArrayInputStream;
import xbird.util.io.FastByteArrayOutputStream;
import xbird.util.string.StringUtils;
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 transient byte[] _exprBytes; // place holder
    private transient BindingVariable _bindingVar;
    private transient XQExpression _bodyExpr;

    private final boolean _redirectable;
    private final List<GridNode> _excludeNodeList;
    private final List<String> _relativePaths;

    // ----------------------------------------
    // injected resources

    @GridKernelResource
    private transient GridKernel grid;
    @GridConfigResource
    private transient GridConfiguration config;
    @GridDirectoryResource
    private transient ILocalDirectory directory;

    // ----------------------------------------

    @SuppressWarnings("unchecked")
    public DispatchQueryExecTask(@CheckForNull GridJob job, @Nonnull BindingVariable bindingVar, @Nonnull XQExpression bodyExpr, @Nonnull byte[] exprBytes, @Nonnull List<String> relativePaths, boolean redirectable) {
        super(job, true);
        assert (bindingVar != null);
        assert (bodyExpr != null);
        assert (exprBytes != null);
        assert (relativePaths != null);
        this._bindingVar = bindingVar;
        this._bodyExpr = bodyExpr;
        this._exprBytes = exprBytes;
        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;
    }

    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(), ie);
            throw new GridException(ie.getMessage(), ie);
        } catch (ExecutionException ee) {
            LOG.error(ee.getMessage(), ee);
            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 = config.getLocalNode();
        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 byte[] k = StringUtils.getBytes(path);
                final GridNodeValueCollector collector = new GridNodeValueCollector(_excludeNodeList);
                try {
                    directory.exactSearch(k, collector);
                } catch (DbException e) {
                    String errmsg = "Exception caused while lookup: " + path;
                    LOG.error(errmsg, e);
                    throw new GridException(errmsg, e);
                }
                final List<GridNode> replicatedNodes = collector.getMatched();
                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, 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, _exprBytes, 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(GridNode localNode, GridTaskRouter router) {
        final GridNode[] liveNodes = router.getAllNodes();
        return GridUtils.selectSuperNodes(liveNodes);
    }

    private void writeObject(ObjectOutputStream s) throws IOException {
        // Write out and any hidden stuff
        s.defaultWriteObject();

        s.writeInt(_exprBytes.length);
        s.write(_exprBytes);
    }

    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
        // Read in any hidden stuff
        s.defaultReadObject();

        final int len = s.readInt();
        final byte[] b = new byte[len];
        s.readFully(b, 0, len);

        FastByteArrayInputStream bis = new FastByteArrayInputStream(b);
        ObjectInputStream ois = new ObjectInputStream(bis);
        this._bodyExpr = (XQExpression) ois.readObject();
        this._bindingVar = (BindingVariable) ois.readObject();

        this._exprBytes = b;
    }

    public static byte[] toBytes(final BindingVariable bindingVar, final XQExpression bodyExpr) {
        final FastByteArrayOutputStream bos = new FastByteArrayOutputStream(8192);
        try {
            final ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(bodyExpr);
            oos.writeObject(bindingVar);
            oos.flush();
        } catch (IOException e) {
            LOG.error(e.getMessage(), e);
            throw new IllegalStateException(e);
        }
        return bos.toByteArray();
    }
}
TOP

Related Classes of xbird.xquery.ext.grid.DispatchQueryExecTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.