Package com.mobixess.jodb.core.query

Source Code of com.mobixess.jodb.core.query.NQExecutor$LoaderCacheKey

/*
Copyright (C) 2007  Mobixess Inc. http://www.java-objects-database.com

This file is part of the JODB (Java Objects Database) open source project.

JODB is free software; you can redistribute it and/or modify it under
the terms of version 2 of the GNU General Public License as published
by the Free Software Foundation.

JODB 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 General Public License
for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package com.mobixess.jodb.core.query;

import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.Comparator;
import java.util.Iterator;
import java.util.WeakHashMap;

import com.mobixess.jodb.core.JODBConfig;
import com.mobixess.jodb.core.JodbIOException;
import com.mobixess.jodb.core.index.IndexDataIterator;
import com.mobixess.jodb.core.index.JODBIndexingAgent;
import com.mobixess.jodb.core.index.JODBIndexingRootAgent;
import com.mobixess.jodb.core.io.IOBase;
import com.mobixess.jodb.core.io.IOTicket;
import com.mobixess.jodb.core.io.JODBOperationContext;
import com.mobixess.jodb.core.query.INqLoader.QueryBytecode;
import com.mobixess.jodb.core.transaction.JODBSession;
import com.mobixess.jodb.core.transaction.JODBSession.ClassDescriptor;
import com.mobixess.jodb.query.api.ObjectSet;
import com.mobixess.jodb.query.api.Predicate;

public class NQExecutor {
   
    private static NQExecutor _instance = new NQExecutor();
    private WeakHashMap<LoaderCacheKey, INqLoader> _loadersCache = new WeakHashMap<LoaderCacheKey, INqLoader>();
    private enum COMPARISON_STATE{UNKNOWN,ASCENDING,DESCENDING,MIXED};
    private static Class<? extends INqLoader> _nqLoaderClass;
   
    private NQExecutor() {
    }
   
    public static void registerLoader(Class<? extends INqLoader> nqLoaderClass){
        _nqLoaderClass = nqLoaderClass;
    }
   
    public static NQExecutor getInstance() {
        return _instance;
    }
   
    @SuppressWarnings("unchecked")
    private Object instantiateSyntheticPredicate(JODBSession session, Object originalPredicate, Class syntheticPredicate) throws Exception{
        ClassDescriptor originalDescriptor = session.getDescriptorForClass(originalPredicate.getClass(), false);
        Object outerInstance = null;
        if(originalDescriptor.isInnerClass()){
            Field outerInstanceAccessField = originalDescriptor.getOuterRefField();
            outerInstance = outerInstanceAccessField!=null ? outerInstanceAccessField.get(originalPredicate) : null;
        }
        ClassDescriptor synthetiClassDescriptor = session.getDescriptorForClass(syntheticPredicate, false);
        return synthetiClassDescriptor.newInstance(outerInstance);
        //Constructor<>
    }
   
    @SuppressWarnings("unchecked")
    public boolean isOptimizedQuery(JODBSession session, Predicate predicate, Comparator comparator) throws IOException{
        JODBOperationContext context = new JODBOperationContext(session, null, null, null,null);
        INqLoader loader = getLoader(context, predicate, comparator);
        return loader.isPredicateOptimized() && loader.isComparatorOptimized();
    }
   
    public QueryBytecode getTransformationForQuery(JODBSession session, Predicate predicate, Comparator comparator) throws IOException{
        if(!isOptimizedQuery(session, predicate, comparator)){
            return null;
        }
        JODBOperationContext context = new JODBOperationContext(session, null, null, null,null);
        INqLoader loader = getLoader(context, predicate, comparator);
        return loader.getTransformedQueryBytecode();
    }
   
    @SuppressWarnings("unchecked")
    public ObjectSet execute(JODBSession session, Predicate predicate, Comparator comparator) throws IOException
    {
        IOBase base = session.getBase();
        IOTicket ticket = base.getIOTicket(true, false);
        try {
            JODBOperationContext context = new JODBOperationContext(session, ticket, null, null,null);
            INqLoader loader = getLoader(context, predicate, comparator);
            if(!loader.isPredicateOptimized() || !loader.isComparatorOptimized()){
                return executeUnoptimized(session, predicate, comparator, loader);
            }
            Class predicateSubjectClass = loader.getPredicateSubjectClass();
            //ClassDescriptor predicateSubjectClassDescriptor = session.getDescriptorForClass(predicateSubjectClass);
            //Method setProxyMethod = loader.getSyntheticProxySetMethod();
            //Class syntheticPredicate;

            Class syntheticPredicateSubjectClass = loader.loadClass(predicateSubjectClass.getName());
            SyntheticSubject syntheticSubject  = new SyntheticSubject(context, loader,syntheticPredicateSubjectClass);
           
            Class syntheticPredicateClass = loader.loadClass(predicate.getClass().getName());
            Predicate syntheticPredicate  = (Predicate) instantiateSyntheticPredicate(session, predicate, syntheticPredicateClass);// (Predicate)syntheticPredicateClass.newInstance();
           
            Comparator syntheticComparator = null;
            if(comparator!=null){
                Class syntheticComparatorClass = loader.loadClass(comparator.getClass().getName());
                syntheticComparator = (Comparator) instantiateSyntheticPredicate(session, comparator, syntheticComparatorClass);
                //(Comparator) session.getDescriptorForClass(syntheticComparatorClass).newInstance();
            }
           
            //int[] predicateSubjectFields = loader.getPredicateSubjectFields();
            JODBIndexingRootAgent indexingRootAgent = session.getIndexingRootAgent();
            JODBIndexingAgent indexingAgent = null;
            Iterator<Integer> predicateSubjectAccessedFields = loader.getAccessedPredicateSubjectFields();
            while (predicateSubjectAccessedFields.hasNext() && indexingAgent == null) {
                indexingAgent = indexingRootAgent.getIndexingAgent(predicateSubjectAccessedFields.next(), session.getBase());
            }
            ByteBuffer indexDataBuffer = null;
            int indexField = -1;
            IndexDataIterator indexIterator = null;
            if(indexingAgent!=null){
                indexField = indexingAgent.getFieldId();
                indexDataBuffer = ByteBuffer.allocate(16);
                indexIterator = indexingAgent.getIndexIterator(true);
            }
           
            if(indexIterator==null){
                indexIterator = new LArrayIndexIterator(base.getForAllObjects(ticket));
            }

            SyntheticSubject syntheticSubjectPrev = null;
            COMPARISON_STATE comparison_state= COMPARISON_STATE.UNKNOWN;
            LArrayChunkedBuffer acceptedIdsBuffer = new LArrayChunkedBuffer();
            while (indexIterator.hasNext()) {
                if(indexDataBuffer != null){
                    indexDataBuffer.clear();
                }
                long nextObjectId = indexIterator.next(indexDataBuffer);

                if(!syntheticSubject.setObjectData(nextObjectId, indexField, indexDataBuffer)){
                    continue;
                }

                if(!syntheticPredicate.match(syntheticSubject._syntheticSubject)){
                    continue;
                }
                acceptedIdsBuffer.add(nextObjectId);
                if(syntheticComparator!=null && comparison_state!=COMPARISON_STATE.MIXED){
                    if(syntheticSubjectPrev!=null ){
                        int compareResult = syntheticComparator.compare(syntheticSubjectPrev._syntheticSubject, syntheticSubject._syntheticSubject);
                        if ((compareResult < 0 && comparison_state == COMPARISON_STATE.DESCENDING)
                                || (compareResult > 0 && comparison_state == COMPARISON_STATE.ASCENDING))
                        {
                            comparison_state = COMPARISON_STATE.MIXED;
                            continue;
                        }else if(compareResult!=0){
                            comparison_state = compareResult < 0? COMPARISON_STATE.ASCENDING : COMPARISON_STATE.DESCENDING;
                        }
                        SyntheticSubject swapHolder = syntheticSubjectPrev;
                        syntheticSubjectPrev = syntheticSubject;
                        syntheticSubject = swapHolder;
                    }else{
                        syntheticSubjectPrev = syntheticSubject;
                        syntheticSubject = new SyntheticSubject(context, loader,syntheticPredicateSubjectClass);
                        continue;
                    }
                   
                }
            }
           
            if(comparator!=null){
                if(comparison_state == COMPARISON_STATE.MIXED){
                    long[] acceptedIds = acceptedIdsBuffer.toArray();
                    acceptedIdsBuffer = null;//for GC
                    NQueryUtils.quickQuerySort(acceptedIds, syntheticComparator, syntheticSubject, syntheticSubjectPrev);
                    return new SimpleArrayQueryList(acceptedIds,session);
                }else if (comparison_state == COMPARISON_STATE.DESCENDING){
                    acceptedIdsBuffer.setIteratorDirection(false);
                }
            }
            return new ChunkedBufferQueryList(acceptedIdsBuffer, session);
        } catch (Exception e) {
            // TODO log
            throw new JodbIOException(e);
        } finally {
            ticket.close();
        }
        //return null;
    }
   
    @SuppressWarnings("unchecked")
    private ObjectSet executeUnoptimized(JODBSession session, Predicate predicate, Comparator comparator, INqLoader loader) throws IOException{
        IOBase base = session.getBase();
        IOTicket ticket = base.getIOTicket(true, false);
        try {

           
            Class predicateSubjectClass = loader.getPredicateSubjectClass();

            JODBIndexingRootAgent indexingRootAgent = session.getIndexingRootAgent();
            JODBIndexingAgent indexingAgent = null;
            Iterator<Integer> predicateSubjectAccessedFields = loader.getAccessedPredicateSubjectFields();
            if(predicateSubjectAccessedFields != null){
                while (predicateSubjectAccessedFields.hasNext() && indexingAgent == null) {//TODO may be useless if analysis incomplete
                    Integer fieldId = predicateSubjectAccessedFields.next();
                    if(fieldId!=null){
                        indexingAgent = indexingRootAgent.getIndexingAgent(fieldId, session.getBase());
                    }
                }
            }

            IndexDataIterator indexIterator = null;
            if(indexingAgent!=null){
                indexIterator = indexingAgent.getIndexIterator(true);
            }
           
            if(indexIterator==null){
                indexIterator = new LArrayIndexIterator(base.getForAllObjects(ticket));
            }

            COMPARISON_STATE comparison_state= COMPARISON_STATE.UNKNOWN;
            LArrayChunkedBuffer acceptedIdsBuffer = new LArrayChunkedBuffer();
            Object previous = null;
            while (indexIterator.hasNext()) {

                long nextObjectId = indexIterator.next(null);
               
                Object obj = session.getObjectForOffset(nextObjectId, JODBConfig.getDefaultActivationDepth());
                //TODO make configurable upon analysis
               
                if(!obj.getClass().isAssignableFrom(predicateSubjectClass)){
                    continue;
                }

                if(!predicate.match(obj)){
                    continue;
                }
                acceptedIdsBuffer.add(nextObjectId);
               
                if(comparator!=null ){
                    if(previous!=null && comparison_state != COMPARISON_STATE.MIXED){
                        int compareResult = comparator.compare(previous, obj);
                        if ((compareResult < 0 && comparison_state == COMPARISON_STATE.DESCENDING)
                                || (compareResult > 0 && comparison_state == COMPARISON_STATE.ASCENDING))
                        {
                            comparison_state = COMPARISON_STATE.MIXED;
                            continue;
                        }else if(compareResult!=0){
                            comparison_state = compareResult < 0? COMPARISON_STATE.ASCENDING : COMPARISON_STATE.DESCENDING;
                        }
                    }
                    previous = obj;
                }
            }
           
            if(comparator!=null){
                if(comparison_state == COMPARISON_STATE.MIXED){
                    long[] acceptedIds = acceptedIdsBuffer.toArray();
                    acceptedIdsBuffer = null;//for GC
                    NQueryUtils.quickQuerySort(acceptedIds, comparator,session);
                    return new SimpleArrayQueryList(acceptedIds,session);
                }else if (comparison_state == COMPARISON_STATE.DESCENDING){
                    acceptedIdsBuffer.setIteratorDirection(false);
                }
            }
            return new ChunkedBufferQueryList(acceptedIdsBuffer, session);
        } catch (Exception e) {
            // TODO log
            throw new JodbIOException(e);
        } finally {
            ticket.close();
        }
    }
   
    private INqLoader getLoader(JODBOperationContext operationContext, Predicate predicate, Comparator comparator) throws IOException{
        LoaderCacheKey cacheKey = new LoaderCacheKey(predicate.getClass(), comparator!=null ? comparator.getClass() : null);//TODO threadlocal for key
        INqLoader loader = _loadersCache.get(cacheKey);
        if(loader == null){
            synchronized (_loadersCache) {
                loader = _loadersCache.get(cacheKey);
                if(loader == null){
                    try {
                        loader = _nqLoaderClass.newInstance();// new NQLoader();
                    } catch (Exception e) {
                        throw new JodbIOException(e);
                    }
                    loader.registerPredicate(operationContext, predicate, comparator);
                    _loadersCache.put(cacheKey, loader);
                }
            }           
        }
        return loader;
    }
   
    static class SyntheticSubject{
        private Object _syntheticSubject;
        private NQueryDataObjectProxy _dataObjectProxy;
       
        public SyntheticSubject(JODBOperationContext context, INqLoader loader, Class syntheticPredicateSubjectClass) throws Exception {
            JODBSession session = context.getSession();
            Field proxyField = loader.getSyntheticProxySetMethod();
            ClassDescriptor syntheticPredicateSubjectClassDescriptor = session.getDescriptorForClass(syntheticPredicateSubjectClass, true, proxyField);
            _syntheticSubject = syntheticPredicateSubjectClassDescriptor.newInstance();
            _dataObjectProxy = new NQueryDataObjectProxy();
            proxyField.set(_syntheticSubject, _dataObjectProxy);
            //setProxyMethod.invoke(_syntheticSubject, _dataObjectProxy);
            _dataObjectProxy.setTargetClass(context, syntheticPredicateSubjectClassDescriptor);
        }
       
        boolean setObjectData(long objectOffset, int indexingField, ByteBuffer indexData) throws IOException {
            return _dataObjectProxy.setObjectData(objectOffset, indexingField, indexData);
        }
       
        Object getSyntheticSubject() {
            return _syntheticSubject;
        }
       
    }
   
    private static class LoaderCacheKey{
        Class _predicate;
        Class _comparator;
        int _hash;
       
        public LoaderCacheKey(Class predicate, Class comparator) {
            set(predicate, comparator);
        }
       
        public void set(Class predicate, Class comparator){
            _predicate = predicate;
            _comparator = comparator;
            calcHashCode();
        }
       
        private void calcHashCode(){
            _hash = _predicate.hashCode();
            if(_comparator!=null){
                _hash+=_comparator.hashCode();
            }
        }
       
        @Override
        public int hashCode() {
            return _hash;
        }
       
        @Override
        public boolean equals(Object obj) {
            if(obj == null){
                return false;
            }
            LoaderCacheKey objKey = (LoaderCacheKey) obj;
            return objKey._predicate == _predicate && objKey._comparator == _comparator;
        }
    }
}
TOP

Related Classes of com.mobixess.jodb.core.query.NQExecutor$LoaderCacheKey

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.
div>