Package xbird.xquery.expr.opt

Source Code of xbird.xquery.expr.opt.PathIndexAccessExpr

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

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;

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

import xbird.storage.DbCollection;
import xbird.storage.DbException;
import xbird.storage.index.Value;
import xbird.storage.indexer.BTreeIndexer;
import xbird.storage.indexer.BasicIndexQuery;
import xbird.storage.indexer.ByteLikeIndexQuery;
import xbird.storage.indexer.IndexMatch;
import xbird.storage.indexer.IndexQuery;
import xbird.util.collections.longs.LongQueue;
import xbird.util.lang.ArrayUtils;
import xbird.util.struct.Pair;
import xbird.xquery.XQRTException;
import xbird.xquery.XQueryException;
import xbird.xquery.dm.dtm.DocumentTableLoader;
import xbird.xquery.dm.dtm.IDocumentTable;
import xbird.xquery.dm.dtm.PagingProfile;
import xbird.xquery.dm.dtm.PagingProfile.Strategy;
import xbird.xquery.dm.instance.DocumentTableModel;
import xbird.xquery.dm.labeling.LabelingHandler;
import xbird.xquery.dm.labeling.RevPathCoder;
import xbird.xquery.dm.value.AbstractSequence;
import xbird.xquery.dm.value.Item;
import xbird.xquery.dm.value.Sequence;
import xbird.xquery.dm.value.XQNode;
import xbird.xquery.expr.AbstractXQExpression;
import xbird.xquery.expr.XQExpression;
import xbird.xquery.meta.DynamicContext;
import xbird.xquery.meta.Focus;
import xbird.xquery.meta.IFocus;
import xbird.xquery.meta.Profiler;
import xbird.xquery.meta.StaticContext;
import xbird.xquery.meta.XQueryContext;
import xbird.xquery.optim.RewriteInfo;
import xbird.xquery.parser.XQueryParserVisitor;
import xbird.xquery.type.Type;

/**
*
* <DIV lang="en"></DIV>
* <DIV lang="ja"></DIV>
*
* @author Makoto YUI (yuin405+xbird@gmail.com)
*/
public class PathIndexAccessExpr extends AbstractXQExpression {
    private static final Log LOG = LogFactory.getLog(PathIndexAccessExpr.class);
    private static final long serialVersionUID = -2778204278710428250L;

    protected final RewriteInfo _accessInfo;
    private final String _accessPath;
    private final byte[] _query;

    public PathIndexAccessExpr(RewriteInfo info, Type type) {
        super();
        this._accessInfo = info;
        byte[] revpath = info.getRewrittedPath();
        this._query = revpath;
        this._accessPath = info.toString(revpath);
        this._type = type;
        this._analyzed = true;
    }

    public XQExpression visit(XQueryParserVisitor visitor, XQueryContext ctxt)
            throws XQueryException {
        return visitor.visit(this, ctxt);
    }

    public XQExpression staticAnalysis(StaticContext statEnv) throws XQueryException {
        return this;
    }

    @Override
    public boolean isPathIndexAccessable(StaticContext statEnv, RewriteInfo info) {
        info.succeeds(_accessInfo);
        return true;
    }

    @Override
    public String toString() {
        return _accessPath;
    }

    public Sequence<? extends Item> eval(Sequence<? extends Item> contextSeq, DynamicContext dynEnv)
            throws XQueryException {
        final IndexQuery idxCond = getIndexCond();
        final List<Pair<DbCollection, String>> lst = _accessInfo.listDocumentsInfo();
        final IndexMatchedSequence seq = new IndexMatchedSequence(dynEnv, idxCond, lst, _type);
        return seq;
    }

    protected IndexQuery getIndexCond() {
        final IndexQuery idxCond;
        final byte[] query = _query;
        final int percentidx = ArrayUtils.indexOf(query, RevPathCoder.PERCENT_CODE, 0);
        if(percentidx < 0) {
            final Value key = new Value(query);
            idxCond = new BasicIndexQuery.IndexConditionEQ(key);
        } else {
            final byte[] keyStr = ArrayUtils.copyOfRange(query, 0, percentidx);
            final byte[] filter = ArrayUtils.copyOfRange(query, percentidx, query.length);
            final Value key = new Value(keyStr);
            idxCond = new ByteLikeIndexQuery(key, filter, RevPathCoder.PERCENT_CODE);
        }
        return idxCond;
    }

    public static class IndexMatchedSequence extends AbstractSequence<XQNode> {
        private static final long serialVersionUID = 911097990361708811L;

        private final IndexQuery idxCond;
        private final List<Pair<DbCollection, String>> lst;
        private final Type type;

        public IndexMatchedSequence(DynamicContext dynEnv, IndexQuery idxCond, List<Pair<DbCollection, String>> lst, Type type) {
            super(dynEnv);
            this.idxCond = idxCond;
            this.lst = lst;
            this.type = type;
        }

        @Override
        public final boolean isEmpty() {
            return super.isEmpty();
        }

        @Override
        public final IFocus<XQNode> iterator() {
            final Iterator<Pair<DbCollection, String>> itor = lst.iterator();
            final IndexMatchFocus resultFocus = new IndexMatchFocus(this, _dynEnv, itor);
            return resultFocus;
        }

        public final boolean next(IFocus<XQNode> focus) throws XQueryException {
            if(focus.reachedEnd()) {
                return false;
            }
            IndexMatchFocus ffcous = (IndexMatchFocus) focus;
            LongQueue pendings = ffcous.getPtrsQueue();
            outer: if(pendings != null && !pendings.isEmpty()) {
                long ptr = pendings.dequeue();
                while(ptr == -1L) {
                    if(pendings.isEmpty()) {
                        break outer;
                    }
                    ptr = pendings.dequeue();
                }
                DocumentTableModel dtm = ffcous.getDocumentTableModel();
                XQNode node = dtm.createNode(ptr);
                ffcous.setContextItem(node);
                return true;
            }
            final Profiler profiler = _dynEnv.getProfiler();
            final Iterator<Pair<DbCollection, String>> itor = ffcous.eachDocument();
            while(itor.hasNext()) {
                final Pair<DbCollection, String> pair = itor.next();
                final DbCollection col = pair.getFirst();
                final String docName = pair.getSecond();
                final File idxFile = getIndexFile(col, docName);
                BTreeIndexer indexer = new BTreeIndexer(idxFile);
                final IndexMatch matched;
                try {
                    matched = indexer.find(idxCond);
                } catch (DbException e) {
                    throw new XQRTException("failed to query index: " + idxFile.getAbsolutePath(), e);
                }
                // TODO REVIEWME sort really required?
                final long[] ptrs = filter(matched.getMatchedUnsorted(), docName, idxFile);
                final int matchCounts = ptrs.length;
                if(LOG.isInfoEnabled()) {
                    LOG.info("Index scan done. matched: " + matched.countMatched() + ", filtered: "
                            + matchCounts);
                }
                if(matchCounts > 0) {
                    final IDocumentTable doctbl;
                    try {
                        doctbl = DocumentTableLoader.load(col, docName, _dynEnv);
                    } catch (IOException e) {
                        throw new XQRTException("failed to load document '" + docName
                                + "' is the collection '" + col.getAbsolutePath() + '\'', e);
                    }
                    final PagingProfile profile = doctbl.getPagingProfile();
                    Strategy origStrategy = null;
                    if(profile != null) {
                        profile.setProfiler(profiler);
                        origStrategy = profile.getStrategy();
                        profile.setStrategy(Strategy.index);
                    }
                    DocumentTableModel dtm = new DocumentTableModel(doctbl, true);
                    final int last = matchCounts - 1;
                    for(int i = 0; i <= last; i++) {
                        long ptr = ptrs[i];
                        if(ptr != -1) {
                            XQNode node = dtm.createNode(ptr);
                            ffcous.setContextItem(node);
                            if(i != last) {
                                LongQueue ptrsQueue = new LongQueue(ptrs, i + 1, last);
                                ffcous.enqueue(dtm, ptrsQueue);
                            }
                            if(profile != null) {
                                profile.setStrategy(origStrategy);
                            }
                            return true;
                        }
                    }
                    if(profile != null) {
                        profile.setStrategy(origStrategy);
                    }
                    return false;
                }
            }
            ffcous.setReachedEnd(true);
            ffcous.clear();
            return false;
        }

        public final int totalCount() throws XQueryException {
            for(Pair<DbCollection, String> pair : lst) {
                final DbCollection col = pair.getFirst();
                final String docName = pair.getSecond();
                final File idxFile = getIndexFile(col, docName);
                BTreeIndexer indexer = new BTreeIndexer(idxFile);
                final IndexMatch matched;
                try {
                    matched = indexer.find(idxCond);
                } catch (DbException e) {
                    throw new XQRTException("failed to query index: " + idxFile.getAbsolutePath(), e);
                }
                final long[] ptrs = filter(matched.getMatchedUnsorted(), docName, idxFile);
                final int matchCounts = ptrs.length;
                if(LOG.isInfoEnabled()) {
                    LOG.info("Index scan done. matched: " + matched.countMatched() + ", filtered: "
                            + matchCounts);
                }
                return matchCounts;
            }
            return 0;
        }

        protected long[] filter(long[] ptrs, String docName, File idxFile) throws XQueryException {
            return ptrs;
        }

        public Type getType() {
            return type;
        }

        private static File getIndexFile(final DbCollection col, final String docName) {
            File idxDir = new File(col.getDirectory(), LabelingHandler.INDEX_DIR_NAME);
            if(!idxDir.exists()) {
                throw new IllegalStateException("Index dir does not exist: "
                        + idxDir.getAbsolutePath());
            }
            File idxFile = new File(idxDir, docName + LabelingHandler.PATHS_FILE_SUFFIX);
            if(!idxFile.exists()) {
                throw new IllegalStateException("Path Index file does not exist: "
                        + idxFile.getAbsolutePath());
            }
            return idxFile;
        }
    }

    private static final class IndexMatchFocus extends Focus<XQNode> {
        private static final long serialVersionUID = -2814427667735216757L;

        private final Iterator<Pair<DbCollection, String>> itor;

        private DocumentTableModel dtm = null;
        private LongQueue ptrsQueue = null;

        public IndexMatchFocus(Sequence<XQNode> src, DynamicContext dynEnv, Iterator<Pair<DbCollection, String>> itor) {
            super(src, dynEnv);
            this.itor = itor;
        }

        public Iterator<Pair<DbCollection, String>> eachDocument() {
            return itor;
        }

        public void enqueue(DocumentTableModel dtm, LongQueue ptrsQueue) {
            this.dtm = dtm;
            this.ptrsQueue = ptrsQueue;
        }

        public LongQueue getPtrsQueue() {
            return ptrsQueue;
        }

        public DocumentTableModel getDocumentTableModel() {
            return dtm;
        }

        public void clear() {
            final IDocumentTable table = dtm.getDocumentTable();
            try {
                table.close();
            } catch (IOException e) {
                LOG.warn(e.getMessage(), e);
            }
            this.dtm = null;
            this.ptrsQueue = null;
        }

    }

}
TOP

Related Classes of xbird.xquery.expr.opt.PathIndexAccessExpr

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.