You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by se...@apache.org on 2014/12/10 16:59:20 UTC

[11/17] incubator-ignite git commit: ignite-qry - merged

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/922a2bab/modules/core/src/main/java/org/gridgain/grid/kernal/managers/indexing/GridIndexingManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/kernal/managers/indexing/GridIndexingManager.java b/modules/core/src/main/java/org/gridgain/grid/kernal/managers/indexing/GridIndexingManager.java
index 3cbeea1..52cb769 100644
--- a/modules/core/src/main/java/org/gridgain/grid/kernal/managers/indexing/GridIndexingManager.java
+++ b/modules/core/src/main/java/org/gridgain/grid/kernal/managers/indexing/GridIndexingManager.java
@@ -9,82 +9,28 @@
 
 package org.gridgain.grid.kernal.managers.indexing;
 
-import org.apache.ignite.lang.*;
-import org.apache.ignite.marshaller.*;
-import org.apache.ignite.portables.*;
 import org.apache.ignite.spi.*;
-import org.apache.ignite.spi.indexing.*;
 import org.gridgain.grid.*;
-import org.gridgain.grid.cache.*;
-import org.gridgain.grid.cache.query.*;
 import org.gridgain.grid.kernal.*;
-import org.gridgain.grid.kernal.managers.*;
-import org.gridgain.grid.kernal.processors.cache.*;
 import org.gridgain.grid.util.*;
-import org.gridgain.grid.util.future.*;
-import org.gridgain.grid.util.lang.*;
-import org.gridgain.grid.util.tostring.*;
-import org.gridgain.grid.util.typedef.*;
 import org.gridgain.grid.util.typedef.internal.*;
-import org.gridgain.grid.util.worker.*;
-import org.jdk8.backport.*;
-import org.jetbrains.annotations.*;
+import org.gridgain.grid.kernal.managers.*;
+import org.apache.ignite.spi.indexing.*;
 
-import java.io.*;
-import java.lang.reflect.*;
 import java.util.*;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.*;
-
-import static org.apache.ignite.spi.indexing.IndexType.*;
 
 /**
  * Manages cache indexing.
  */
-public class GridIndexingManager extends GridManagerAdapter<IndexingSpi> {
-    /** */
-    private IgniteMarshaller marsh;
-
-    /** Type descriptors. */
-    private final ConcurrentMap<TypeId, TypeDescriptor> types = new ConcurrentHashMap8<>();
-
-    /** Type descriptors. */
-    private final ConcurrentMap<TypeName, TypeDescriptor> typesByName = new ConcurrentHashMap8<>();
-
-    /** */
-    private final ConcurrentMap<Long, ClassLoader> ldrById = new ConcurrentHashMap8<>();
-
-    /** */
-    private final ConcurrentMap<ClassLoader, Long> idByLdr = new ConcurrentHashMap8<>();
-
-    /** */
-    private final AtomicLong ldrIdGen = new AtomicLong();
-
+public class GridIndexingManager extends GridManagerAdapter<GridIndexingSpi> {
     /** */
     private final GridSpinBusyLock busyLock = new GridSpinBusyLock();
 
-    /** Configuration-declared types. */
-    private Map<TypeId, GridCacheQueryTypeMetadata> declaredTypesById;
-
-    /** Configuration-declared types. */
-    private final Map<TypeName, GridCacheQueryTypeMetadata> declaredTypesByName = new HashMap<>();
-
-    /** Portable IDs. */
-    private Map<Integer, String> portableIds;
-
-    /** Type resolvers per space name. */
-    private Map<String, GridCacheQueryTypeResolver> typeResolvers = new HashMap<>();
-
-    /** */
-    private ExecutorService execSvc;
-
     /**
      * @param ctx  Kernal context.
      */
     public GridIndexingManager(GridKernalContext ctx) {
         super(ctx, ctx.config().getIndexingSpi());
-
-        marsh = ctx.config().getMarshaller();
     }
 
     /**
@@ -95,33 +41,10 @@ public class GridIndexingManager extends GridManagerAdapter<IndexingSpi> {
             return;
 
         if (!enabled())
-            U.warn(log, "Indexing is disabled (to enable please configure GridH2IndexingSpi).");
-
-        IndexingMarshaller m = new IdxMarshaller();
-
-        for (IndexingSpi spi : getSpis()) {
-            spi.registerMarshaller(m);
-
-            for (GridCacheConfiguration cacheCfg : ctx.config().getCacheConfiguration())
-                spi.registerSpace(cacheCfg.getName());
-        }
-
-        execSvc = ctx.config().getExecutorService();
+            U.warn(log, "Indexing is disabled (to enable please configure GridIndexingSpi).");
 
         startSpi();
 
-        for (GridCacheConfiguration ccfg : ctx.config().getCacheConfiguration()){
-            GridCacheQueryConfiguration qryCfg = ccfg.getQueryConfiguration();
-
-            if (qryCfg != null) {
-                for (GridCacheQueryTypeMetadata meta : qryCfg.getTypeMetadata())
-                    declaredTypesByName.put(new TypeName(ccfg.getName(), meta.getType()), meta);
-
-                if (qryCfg.getTypeResolver() != null)
-                    typeResolvers.put(ccfg.getName(), qryCfg.getTypeResolver());
-            }
-        }
-
         if (log.isDebugEnabled())
             log.debug(startInfo());
     }
@@ -148,162 +71,22 @@ public class GridIndexingManager extends GridManagerAdapter<IndexingSpi> {
     }
 
     /**
-     * Returns number of objects of given type for given space of spi.
-     *
-     * @param spi SPI Name.
-     * @param space Space.
-     * @param valType Value type.
-     * @return Objects number or -1 if this type is unknown for given SPI and space.
-     * @throws GridException If failed.
-     */
-    public long size(@Nullable String spi, @Nullable String space, Class<?> valType) throws GridException {
-        if (!busyLock.enterBusy())
-            throw new IllegalStateException("Failed to get space size (grid is stopping).");
-
-        try {
-            TypeDescriptor desc = types.get(new TypeId(space, valType));
-
-            if (desc == null || !desc.registered())
-                return -1;
-
-            return getSpi(spi).size(space, desc);
-        }
-        finally {
-            busyLock.leaveBusy();
-        }
-    }
-
-    /**
-     * Rebuilds all search indexes of given value type for given space of spi.
-     *
-     * @param spi SPI name.
-     * @param space Space.
-     * @param valTypeName Value type name.
-     * @return Future that will be completed when rebuilding of all indexes is finished.
-     */
-    public IgniteFuture<?> rebuildIndexes(@Nullable final String spi, @Nullable final String space, String valTypeName) {
-        if (!busyLock.enterBusy())
-            throw new IllegalStateException("Failed to rebuild indexes (grid is stopping).");
-
-        try {
-            return rebuildIndexes(spi, space, typesByName.get(new TypeName(space, valTypeName)));
-        }
-        finally {
-            busyLock.leaveBusy();
-        }
-    }
-
-    /**
-     * @param spi SPI name.
-     * @param space Space.
-     * @param desc Type descriptor.
-     * @return Future that will be completed when rebuilding of all indexes is finished.
-     */
-    private IgniteFuture<?> rebuildIndexes(@Nullable final String spi, @Nullable final String space,
-        @Nullable final TypeDescriptor desc) {
-        if (desc == null || !desc.registered())
-            return new GridFinishedFuture<Void>(ctx);
-
-        final GridWorkerFuture<?> fut = new GridWorkerFuture<Void>();
-
-        GridWorker w = new GridWorker(ctx.gridName(), "index-rebuild-worker", log) {
-            @Override protected void body() {
-                try {
-                    getSpi(spi).rebuildIndexes(space, desc);
-
-                    fut.onDone();
-                }
-                catch (Exception e) {
-                    fut.onDone(e);
-                }
-                catch (Throwable e) {
-                    log.error("Failed to rebuild indexes for type: " + desc.name(), e);
-
-                    fut.onDone(e);
-                }
-            }
-        };
-
-        fut.setWorker(w);
-
-        execSvc.execute(w);
-
-        return fut;
-    }
-
-    /**
-     * Rebuilds all search indexes for given spi.
-     *
-     * @param spi SPI name.
-     * @return Future that will be completed when rebuilding of all indexes is finished.
-     */
-    @SuppressWarnings("unchecked")
-    public IgniteFuture<?> rebuildAllIndexes(@Nullable String spi) {
-        if (!busyLock.enterBusy())
-            throw new IllegalStateException("Failed to get space size (grid is stopping).");
-
-        try {
-            GridCompoundFuture<?, ?> fut = new GridCompoundFuture<Object, Object>(ctx);
-
-            for (Map.Entry<TypeId, TypeDescriptor> e : types.entrySet())
-                fut.add((IgniteFuture)rebuildIndexes(spi, e.getKey().space, e.getValue()));
-
-            fut.markInitialized();
-
-            return fut;
-        }
-        finally {
-            busyLock.leaveBusy();
-        }
-    }
-
-    /**
-     * FOR TESTING ONLY
-     *
-     * @param name SPI Name.
-     * @return SPI.
-     */
-    public IndexingSpi spi(@Nullable String name) {
-        if (F.isEmpty(name))
-            return getSpis()[0];
-
-        for (IndexingSpi s : getSpis()) {
-            if (name.equals(s.getName()))
-                return s;
-        }
-
-        throw new GridRuntimeException("Failed to find SPI for name: " + name);
-    }
-
-    /**
-     * @param x Value.
-     * @param bytes Serialized value.
-     * @param <T> Value type.
-     * @return Index entry.
-     */
-    private <T> IndexingEntity<T> entry(T x, @Nullable byte[] bytes) {
-        return new IndexingEntityAdapter<>(x, bytes);
-    }
-
-    /**
      * Writes key-value pair to index.
      *
-     * @param spi SPI Name.
      * @param space Space.
      * @param key Key.
-     * @param keyBytes Byte array with key data.
      * @param val Value.
-     * @param valBytes Byte array with value data.
-     * @param ver Cache entry version.
      * @param expirationTime Expiration time or 0 if never expires.
      * @throws GridException In case of error.
      */
     @SuppressWarnings("unchecked")
-    public <K, V> void store(final String spi, final String space, final K key, @Nullable byte[] keyBytes, final V val,
-        @Nullable byte[] valBytes, byte[] ver, long expirationTime) throws GridException {
+    public <K, V> void store(final String space, final K key, final V val, long expirationTime) throws GridException {
         assert key != null;
         assert val != null;
 
+        if (!enabled())
+            return;
+
         if (!busyLock.enterBusy())
             throw new IllegalStateException("Failed to write to index (grid is stopping).");
 
@@ -311,125 +94,7 @@ public class GridIndexingManager extends GridManagerAdapter<IndexingSpi> {
             if (log.isDebugEnabled())
                 log.debug("Storing key to cache query index [key=" + key + ", value=" + val + "]");
 
-            final Class<?> valCls = val.getClass();
-            final Class<?> keyCls = key.getClass();
-
-            TypeId id = null;
-
-            GridCacheQueryTypeResolver rslvr = typeResolvers.get(space);
-
-            if (rslvr != null) {
-                String typeName = rslvr.resolveTypeName(key, val);
-
-                if (typeName != null)
-                    id = new TypeId(space, ctx.portable().typeId(typeName));
-            }
-
-            if (id == null) {
-                if (val instanceof PortableObject) {
-                    PortableObject portable = (PortableObject)val;
-
-                    int typeId = portable.typeId();
-
-                    String typeName = portableName(typeId);
-
-                    if (typeName == null)
-                        return;
-
-                    id = new TypeId(space, typeId);
-                }
-                else
-                    id = new TypeId(space, valCls);
-            }
-
-            TypeDescriptor desc = types.get(id);
-
-            if (desc == null) {
-                desc = new TypeDescriptor();
-
-                TypeDescriptor existing = types.putIfAbsent(id, desc);
-
-                if (existing != null)
-                    desc = existing;
-            }
-
-            if (!desc.succeeded()) {
-                final TypeDescriptor d = desc;
-
-                d.init(new Callable<Void>() {
-                    @Override public Void call() throws Exception {
-                        d.keyClass(keyCls);
-                        d.valueClass(valCls);
-
-                        if (key instanceof PortableObject) {
-                            PortableObject portableKey = (PortableObject)key;
-
-                            String typeName = portableName(portableKey.typeId());
-
-                            if (typeName != null) {
-                                GridCacheQueryTypeMetadata keyMeta = declaredType(space, portableKey.typeId());
-
-                                if (keyMeta != null)
-                                    processPortableMeta(true, keyMeta, d);
-                            }
-                        }
-                        else {
-                            GridCacheQueryTypeMetadata keyMeta = declaredType(space, keyCls.getName());
-
-                            if (keyMeta == null)
-                                processAnnotationsInClass(true, d.keyCls, d, null);
-                            else
-                                processClassMeta(true, d.keyCls, keyMeta, d);
-                        }
-
-                        if (val instanceof PortableObject) {
-                            PortableObject portableVal = (PortableObject)val;
-
-                            String typeName = portableName(portableVal.typeId());
-
-                            if (typeName != null) {
-                                GridCacheQueryTypeMetadata valMeta = declaredType(space, portableVal.typeId());
-
-                                d.name(typeName);
-
-                                if (valMeta != null)
-                                    processPortableMeta(false, valMeta, d);
-                            }
-                        }
-                        else {
-                            String valTypeName = typeName(valCls);
-
-                            d.name(valTypeName);
-
-                            GridCacheQueryTypeMetadata typeMeta = declaredType(space, valCls.getName());
-
-                            if (typeMeta == null)
-                                processAnnotationsInClass(false, d.valCls, d, null);
-                            else
-                                processClassMeta(false, d.valCls, typeMeta, d);
-                        }
-
-                        d.registered(getSpi(spi).registerType(space, d));
-
-                        typesByName.put(new TypeName(space, d.name()), d);
-
-                        return null;
-                    }
-                });
-            }
-
-            if (!desc.registered())
-                return;
-
-            if (!desc.valueClass().equals(valCls))
-                throw new GridException("Failed to update index due to class name conflict" +
-                    "(multiple classes with same simple name are stored in the same cache) " +
-                    "[expCls=" + desc.valueClass().getName() + ", actualCls=" + valCls.getName() + ']');
-
-            IndexingEntity<K> k = entry(key, keyBytes);
-            IndexingEntity<V> v = entry(val, valBytes);
-
-            getSpi(spi).store(space, desc, k, v, ver, expirationTime);
+            getSpi().store(space, key, val, expirationTime);
         }
         finally {
             busyLock.leaveBusy();
@@ -437,138 +102,22 @@ public class GridIndexingManager extends GridManagerAdapter<IndexingSpi> {
     }
 
     /**
-     * Gets type name by class.
-     *
-     * @param cls Class.
-     * @return Type name.
-     */
-    public String typeName(Class<?> cls) {
-        String typeName = cls.getSimpleName();
-
-        // To protect from failure on anonymous classes.
-        if (F.isEmpty(typeName)) {
-            String pkg = cls.getPackage().getName();
-
-            typeName = cls.getName().substring(pkg.length() + (pkg.isEmpty() ? 0 : 1));
-        }
-
-        if (cls.isArray()) {
-            assert typeName.endsWith("[]");
-
-            typeName = typeName.substring(0, typeName.length() - 2) + "_array";
-        }
-
-        return typeName;
-    }
-
-    /**
-     * Gets portable type name by portable ID.
-     *
-     * @param typeId Type ID.
-     * @return Name.
-     */
-    private String portableName(int typeId) {
-        Map<Integer, String> portableIds = this.portableIds;
-
-        if (portableIds == null) {
-            portableIds = new HashMap<>();
-
-            for (GridCacheConfiguration ccfg : ctx.config().getCacheConfiguration()){
-                GridCacheQueryConfiguration qryCfg = ccfg.getQueryConfiguration();
-
-                if (qryCfg != null) {
-                    for (GridCacheQueryTypeMetadata meta : qryCfg.getTypeMetadata())
-                        portableIds.put(ctx.portable().typeId(meta.getType()), meta.getType());
-                }
-            }
-
-            this.portableIds = portableIds;
-        }
-
-        return portableIds.get(typeId);
-    }
-
-    /**
-     * @param space Space name.
-     * @param typeId Type ID.
-     * @return Type meta data if it was declared in configuration.
-     */
-    @Nullable private GridCacheQueryTypeMetadata declaredType(String space, int typeId) {
-        Map<TypeId, GridCacheQueryTypeMetadata> declaredTypesById = this.declaredTypesById;
-
-        if (declaredTypesById == null) {
-            declaredTypesById = new HashMap<>();
-
-            for (GridCacheConfiguration ccfg : ctx.config().getCacheConfiguration()){
-                GridCacheQueryConfiguration qryCfg = ccfg.getQueryConfiguration();
-
-                if (qryCfg != null) {
-                    for (GridCacheQueryTypeMetadata meta : qryCfg.getTypeMetadata())
-                        declaredTypesById.put(new TypeId(ccfg.getName(), ctx.portable().typeId(meta.getType())), meta);
-                }
-            }
-
-            this.declaredTypesById = declaredTypesById;
-        }
-
-        return declaredTypesById.get(new TypeId(space, typeId));
-    }
-
-    /**
-     * @param space Space name.
-     * @param typeName Type name.
-     * @return Type meta data if it was declared in configuration.
-     */
-    @Nullable private GridCacheQueryTypeMetadata declaredType(String space, String typeName) {
-        return declaredTypesByName.get(new TypeName(space, typeName));
-    }
-
-    /**
-     * @param spi SPI Name.
      * @param space Space.
      * @param key Key.
-     * @param keyBytes Byte array with key value.
-     * @return {@code true} if key was found and removed, otherwise {@code false}.
      * @throws GridException Thrown in case of any errors.
      */
     @SuppressWarnings("unchecked")
-    public <K> boolean remove(String spi, String space, K key, @Nullable byte[] keyBytes) throws GridException {
+    public void remove(String space, Object key) throws GridException {
         assert key != null;
 
-        if (!busyLock.enterBusy())
-            throw new IllegalStateException("Failed to remove from index (grid is stopping).");
-
-        try {
-            IndexingEntity<K> k = entry(key, keyBytes);
-
-            return getSpi(spi).remove(space, k);
-        }
-        finally {
-            busyLock.leaveBusy();
-        }
-    }
+        if (!enabled())
+            return;
 
-    /**
-     * @param spi SPI Name.
-     * @param space Space name.
-     * @param clause Clause.
-     * @param params Parameters collection.
-     * @param includeBackups Include or exclude backup entries.
-     * @param filters Key and value filters.
-     * @return Field rows.
-     * @throws GridException If failed.
-     */
-    public <K, V> IndexingFieldsResult queryFields(@Nullable String spi, @Nullable String space,
-        String clause, Collection<Object> params, boolean includeBackups,
-        IndexingQueryFilter filters) throws GridException {
         if (!busyLock.enterBusy())
-            throw new IllegalStateException("Failed to execute query (grid is stopping).");
+            throw new IllegalStateException("Failed to remove from index (grid is stopping).");
 
         try {
-            IndexingQueryFilter backupFilter = backupsFilter(includeBackups);
-
-            return getSpi(spi).queryFields(space, clause, params,
-                and(filters, backupFilter));
+            getSpi().remove(space, key);
         }
         finally {
             busyLock.leaveBusy();
@@ -576,103 +125,51 @@ public class GridIndexingManager extends GridManagerAdapter<IndexingSpi> {
     }
 
     /**
-     * @param f1 First filter.
-     * @param f2 Second filter.
-     * @return And filter of the given two.
-     */
-    @Nullable private static IndexingQueryFilter and(@Nullable final IndexingQueryFilter f1,
-        @Nullable final IndexingQueryFilter f2) {
-        if (f1 == null)
-            return f2;
-
-        if (f2 == null)
-            return f1;
-
-        return new IndexingQueryFilter() {
-            @Nullable @Override public <K, V> IgniteBiPredicate<K, V> forSpace(String spaceName) throws GridException {
-                final IgniteBiPredicate<K, V> fltr1 = f1.forSpace(spaceName);
-                final IgniteBiPredicate<K, V> fltr2 = f2.forSpace(spaceName);
-
-                if (fltr1 == null)
-                    return fltr2;
-
-                if (fltr2 == null)
-                    return fltr1;
-
-                return new IgniteBiPredicate<K, V>() {
-                    @Override public boolean apply(K k, V v) {
-                        return fltr1.apply(k, v) && fltr2.apply(k, v);
-                    }
-                };
-            }
-        };
-    }
-
-    /**
-     * @param spi SPI Name.
      * @param space Space.
-     * @param clause Clause.
      * @param params Parameters collection.
-     * @param resType Result type.
-     * @param includeBackups Include or exclude backup entries.
      * @param filters Filters.
-     * @param <K> Key type.
-     * @param <V> Value type.
-     * @return Key/value rows.
+     * @return Query result.
      * @throws GridException If failed.
      */
     @SuppressWarnings("unchecked")
-    public <K, V> GridCloseableIterator<IndexingKeyValueRow<K, V>> query(String spi, String space, String clause,
-        Collection<Object> params, String resType, boolean includeBackups,
-        IndexingQueryFilter filters) throws GridException {
+    public IgniteSpiCloseableIterator<?> query(String space, Collection<Object> params, GridIndexingQueryFilter filters)
+        throws GridException {
+        if (!enabled())
+            throw new GridException("Indexing SPI is not configured.");
+
         if (!busyLock.enterBusy())
             throw new IllegalStateException("Failed to execute query (grid is stopping).");
 
         try {
-            TypeDescriptor type = typesByName.get(new TypeName(space, resType));
+            final Iterator<?> res = getSpi().query(space, params, filters);
 
-            if (type == null || !type.registered())
+            if (res == null)
                 return new GridEmptyCloseableIterator<>();
 
-            IndexingQueryFilter backupFilter = backupsFilter(includeBackups);
-
-            return new GridSpiCloseableIteratorWrapper<>(getSpi(spi).<K,V>query(space, clause, params, type,
-                and(filters, backupFilter)));
-        }
-        finally {
-            busyLock.leaveBusy();
-        }
-    }
-
-    /**
-     * @param spi SPI Name.
-     * @param space Space.
-     * @param clause Clause.
-     * @param resType Result type.
-     * @param includeBackups Include or exclude backup entries.
-     * @param filters Key and value filters.
-     * @param <K> Key type.
-     * @param <V> Value type.
-     * @return Key/value rows.
-     * @throws GridException If failed.
-     */
-    @SuppressWarnings("unchecked")
-    public <K, V> GridCloseableIterator<IndexingKeyValueRow<K, V>> queryText(String spi, String space,
-        String clause, String resType, boolean includeBackups,
-        IndexingQueryFilter filters) throws GridException {
-        if (!busyLock.enterBusy())
-            throw new IllegalStateException("Failed to execute query (grid is stopping).");
-
-        try {
-            TypeDescriptor type = typesByName.get(new TypeName(space, resType));
+            return new IgniteSpiCloseableIterator<Object>() {
+                @Override public void close() throws GridException {
+                    if (res instanceof AutoCloseable) {
+                        try {
+                            ((AutoCloseable)res).close();
+                        }
+                        catch (Exception e) {
+                            throw new GridException(e);
+                        }
+                    }
+                }
 
-            if (type == null || !type.registered())
-                return new GridEmptyCloseableIterator<>();
+                @Override public boolean hasNext() {
+                    return res.hasNext();
+                }
 
-            IndexingQueryFilter backupFilter = backupsFilter(includeBackups);
+                @Override public Object next() {
+                    return res.next();
+                }
 
-            return new GridSpiCloseableIteratorWrapper<>(getSpi(spi).<K,V>queryText(space, clause, type,
-                and(filters, backupFilter)));
+                @Override public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+            };
         }
         finally {
             busyLock.leaveBusy();
@@ -680,47 +177,21 @@ public class GridIndexingManager extends GridManagerAdapter<IndexingSpi> {
     }
 
     /**
-     * @param <K> Key type.
-     * @param <V> Value type.
-     * @return Predicate.
-     * @param includeBackups Include backups.
-     */
-    @SuppressWarnings("unchecked")
-    @Nullable private <K, V> IndexingQueryFilter backupsFilter(boolean includeBackups) {
-        if (includeBackups)
-            return null;
-
-        return new IndexingQueryFilter() {
-            @Nullable @Override public IgniteBiPredicate<K, V> forSpace(final String spaceName) {
-                final GridCacheAdapter<Object, Object> cache = ctx.cache().internalCache(spaceName);
-
-                if (cache.context().isReplicated() || cache.configuration().getBackups() == 0)
-                    return null;
-
-                return new IgniteBiPredicate<K, V>() {
-                    @Override public boolean apply(K k, V v) {
-                        return cache.context().affinity().primary(ctx.discovery().localNode(), k, -1);
-                    }
-                };
-            }
-        };
-    }
-
-    /**
      * Will be called when entry for key will be swapped.
      *
-     * @param spi Spi name.
      * @param spaceName Space name.
-     * @param swapSpaceName Swap space name.
      * @param key key.
-     * @throws org.apache.ignite.spi.IgniteSpiException If failed.
+     * @throws IgniteSpiException If failed.
      */
-    public void onSwap(String spi, String spaceName, String swapSpaceName, Object key) throws IgniteSpiException {
+    public void onSwap(String spaceName, Object key) throws IgniteSpiException {
+        if (!enabled())
+            return;
+
         if (!busyLock.enterBusy())
             throw new IllegalStateException("Failed to process swap event (grid is stopping).");
 
         try {
-            getSpi(spi).onSwap(spaceName, swapSpaceName, key);
+            getSpi().onSwap(spaceName, key);
         }
         finally {
             busyLock.leaveBusy();
@@ -730,1163 +201,24 @@ public class GridIndexingManager extends GridManagerAdapter<IndexingSpi> {
     /**
      * Will be called when entry for key will be unswapped.
      *
-     * @param spi Spi name.
      * @param spaceName Space name.
      * @param key Key.
      * @param val Value.
-     * @param valBytes Value bytes.
-     * @throws org.apache.ignite.spi.IgniteSpiException If failed.
+     * @throws IgniteSpiException If failed.
      */
-    public void onUnswap(String spi, String spaceName, Object key, Object val, byte[] valBytes)
+    public void onUnswap(String spaceName, Object key, Object val)
         throws IgniteSpiException {
-        if (!busyLock.enterBusy())
-            throw new IllegalStateException("Failed to process swap event (grid is stopping).");
-
-        try {
-            getSpi(spi).onUnswap(spaceName, key, val, valBytes);
-        }
-        finally {
-            busyLock.leaveBusy();
-        }
-    }
+        if (!enabled())
+            return;
 
-    /**
-     * Removes index tables for all classes belonging to given class loader.
-     *
-     * @param space Space name.
-     * @param ldr Class loader to undeploy.
-     * @throws GridException If undeploy failed.
-     */
-    public void onUndeploy(@Nullable String space, ClassLoader ldr) throws GridException {
         if (!busyLock.enterBusy())
-            throw new IllegalStateException("Failed to process undeploy event (grid is stopping).");
+            throw new IllegalStateException("Failed to process swap event (grid is stopping).");
 
         try {
-            try {
-                Iterator<Map.Entry<TypeId, TypeDescriptor>> it = types.entrySet().iterator();
-
-                while (it.hasNext()) {
-                    Map.Entry<TypeId, TypeDescriptor> e = it.next();
-
-                    if (!F.eq(e.getKey().space, space))
-                        continue;
-
-                    TypeDescriptor desc = e.getValue();
-
-                    if (ldr.equals(U.detectClassLoader(desc.valCls)) || ldr.equals(U.detectClassLoader(desc.keyCls))) {
-                        for (IndexingSpi spi : getSpis()) {
-                            if (desc.await() && desc.registered())
-                                spi.unregisterType(e.getKey().space, desc);
-                        }
-
-                        it.remove();
-                    }
-                }
-            }
-            finally {
-                Long id = idByLdr.remove(ldr);
-
-                if (id != null)
-                    ldrById.remove(id);
-            }
+            getSpi().onUnswap(spaceName, key, val);
         }
         finally {
             busyLock.leaveBusy();
         }
     }
-
-    /**
-     * Process annotations for class.
-     *
-     * @param key If given class relates to key.
-     * @param cls Class.
-     * @param type Type descriptor.
-     * @param parent Parent in case of embeddable.
-     * @throws GridException In case of error.
-     */
-    static void processAnnotationsInClass(boolean key, Class<?> cls, TypeDescriptor type,
-        @Nullable ClassProperty parent) throws GridException {
-        if (U.isJdk(cls))
-            return;
-
-        if (parent != null && parent.knowsClass(cls))
-            throw new GridException("Recursive reference found in type: " + cls.getName());
-
-        if (parent == null) { // Check class annotation at top level only.
-            GridCacheQueryTextField txtAnnCls = cls.getAnnotation(GridCacheQueryTextField.class);
-
-            if (txtAnnCls != null)
-                type.valueTextIndex(true);
-
-            GridCacheQueryGroupIndex grpIdx = cls.getAnnotation(GridCacheQueryGroupIndex.class);
-
-            if (grpIdx != null)
-                type.addIndex(grpIdx.name(), SORTED);
-
-            GridCacheQueryGroupIndex.List grpIdxList = cls.getAnnotation(GridCacheQueryGroupIndex.List.class);
-
-            if (grpIdxList != null && !F.isEmpty(grpIdxList.value())) {
-                for (GridCacheQueryGroupIndex idx : grpIdxList.value())
-                    type.addIndex(idx.name(), SORTED);
-            }
-        }
-
-        for (Class<?> c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) {
-            for (Field field : c.getDeclaredFields()) {
-                GridCacheQuerySqlField sqlAnn = field.getAnnotation(GridCacheQuerySqlField.class);
-                GridCacheQueryTextField txtAnn = field.getAnnotation(GridCacheQueryTextField.class);
-
-                if (sqlAnn != null || txtAnn != null) {
-                    ClassProperty prop = new ClassProperty(field);
-
-                    prop.parent(parent);
-
-                    processAnnotation(key, sqlAnn, txtAnn, field.getType(), prop, type);
-
-                    type.addProperty(key, prop, true);
-                }
-            }
-
-            for (Method mtd : c.getDeclaredMethods()) {
-                GridCacheQuerySqlField sqlAnn = mtd.getAnnotation(GridCacheQuerySqlField.class);
-                GridCacheQueryTextField txtAnn = mtd.getAnnotation(GridCacheQueryTextField.class);
-
-                if (sqlAnn != null || txtAnn != null) {
-                    if (mtd.getParameterTypes().length != 0)
-                        throw new GridException("Getter with GridCacheQuerySqlField " +
-                            "annotation cannot have parameters: " + mtd);
-
-                    ClassProperty prop = new ClassProperty(mtd);
-
-                    prop.parent(parent);
-
-                    processAnnotation(key, sqlAnn, txtAnn, mtd.getReturnType(), prop, type);
-
-                    type.addProperty(key, prop, true);
-                }
-            }
-        }
-    }
-
-    /**
-     * Processes annotation at field or method.
-     *
-     * @param key If given class relates to key.
-     * @param sqlAnn SQL annotation, can be {@code null}.
-     * @param txtAnn H2 text annotation, can be {@code null}.
-     * @param cls Class of field or return type for method.
-     * @param prop Current property.
-     * @param desc Class description.
-     * @throws GridException In case of error.
-     */
-    static void processAnnotation(boolean key, GridCacheQuerySqlField sqlAnn, GridCacheQueryTextField txtAnn,
-        Class<?> cls, ClassProperty prop, TypeDescriptor desc) throws GridException {
-        if (sqlAnn != null) {
-            processAnnotationsInClass(key, cls, desc, prop);
-
-            if (!sqlAnn.name().isEmpty())
-                prop.name(sqlAnn.name());
-
-            if (sqlAnn.index() || sqlAnn.unique()) {
-                String idxName = prop.name() + "_idx";
-
-                desc.addIndex(idxName, isGeometryClass(prop.type()) ? GEO_SPATIAL : SORTED);
-
-                desc.addFieldToIndex(idxName, prop.name(), 0, sqlAnn.descending());
-            }
-
-            if (!F.isEmpty(sqlAnn.groups())) {
-                for (String group : sqlAnn.groups())
-                    desc.addFieldToIndex(group, prop.name(), 0, false);
-            }
-
-            if (!F.isEmpty(sqlAnn.orderedGroups())) {
-                for (GridCacheQuerySqlField.Group idx : sqlAnn.orderedGroups())
-                    desc.addFieldToIndex(idx.name(), prop.name(), idx.order(), idx.descending());
-            }
-        }
-
-        if (txtAnn != null)
-            desc.addFieldToTextIndex(prop.name());
-    }
-
-    /**
-     * Processes declarative metadata for class.
-     *
-     * @param key Key or value flag.
-     * @param cls Class to process.
-     * @param meta Type metadata.
-     * @param d Type descriptor.
-     * @throws GridException If failed.
-     */
-    static void processClassMeta(boolean key, Class<?> cls, GridCacheQueryTypeMetadata meta, TypeDescriptor d)
-        throws GridException {
-        for (Map.Entry<String, Class<?>> entry : meta.getAscendingFields().entrySet()) {
-            ClassProperty prop = buildClassProperty(cls, entry.getKey(), entry.getValue());
-
-            d.addProperty(key, prop, false);
-
-            String idxName = prop.name() + "_idx";
-
-            d.addIndex(idxName, isGeometryClass(prop.type()) ? GEO_SPATIAL : SORTED);
-
-            d.addFieldToIndex(idxName, prop.name(), 0, false);
-        }
-
-        for (Map.Entry<String, Class<?>> entry : meta.getDescendingFields().entrySet()) {
-            ClassProperty prop = buildClassProperty(cls, entry.getKey(), entry.getValue());
-
-            d.addProperty(key, prop, false);
-
-            String idxName = prop.name() + "_idx";
-
-            d.addIndex(idxName, isGeometryClass(prop.type()) ? GEO_SPATIAL : SORTED);
-
-            d.addFieldToIndex(idxName, prop.name(), 0, true);
-        }
-
-        for (String txtIdx : meta.getTextFields()) {
-            ClassProperty prop = buildClassProperty(cls, txtIdx, String.class);
-
-            d.addProperty(key, prop, false);
-
-            d.addFieldToTextIndex(prop.name());
-        }
-
-        Map<String, LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>>> grps = meta.getGroups();
-
-        if (grps != null) {
-            for (Map.Entry<String, LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>>> entry : grps.entrySet()) {
-                String idxName = entry.getKey();
-
-                LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>> idxFields = entry.getValue();
-
-                int order = 0;
-
-                for (Map.Entry<String, IgniteBiTuple<Class<?>, Boolean>> idxField : idxFields.entrySet()) {
-                    ClassProperty prop = buildClassProperty(cls, idxField.getKey(), idxField.getValue().get1());
-
-                    d.addProperty(key, prop, false);
-
-                    Boolean descending = idxField.getValue().get2();
-
-                    d.addFieldToIndex(idxName, prop.name(), order, descending != null && descending);
-
-                    order++;
-                }
-            }
-        }
-
-        for (Map.Entry<String, Class<?>> entry : meta.getQueryFields().entrySet()) {
-            ClassProperty prop = buildClassProperty(cls, entry.getKey(), entry.getValue());
-
-            d.addProperty(key, prop, false);
-        }
-    }
-
-    /**
-     * Processes declarative metadata for portable object.
-     *
-     * @param key Key or value flag.
-     * @param meta Declared metadata.
-     * @param d Type descriptor.
-     * @throws GridException If failed.
-     */
-    static void processPortableMeta(boolean key, GridCacheQueryTypeMetadata meta, TypeDescriptor d)
-        throws GridException {
-        for (Map.Entry<String, Class<?>> entry : meta.getAscendingFields().entrySet()) {
-            PortableProperty prop = buildPortableProperty(entry.getKey(), entry.getValue());
-
-            d.addProperty(key, prop, false);
-
-            String idxName = prop.name() + "_idx";
-
-            d.addIndex(idxName, isGeometryClass(prop.type()) ? GEO_SPATIAL : SORTED);
-
-            d.addFieldToIndex(idxName, prop.name(), 0, false);
-        }
-
-        for (Map.Entry<String, Class<?>> entry : meta.getDescendingFields().entrySet()) {
-            PortableProperty prop = buildPortableProperty(entry.getKey(), entry.getValue());
-
-            d.addProperty(key, prop, false);
-
-            String idxName = prop.name() + "_idx";
-
-            d.addIndex(idxName, isGeometryClass(prop.type()) ? GEO_SPATIAL : SORTED);
-
-            d.addFieldToIndex(idxName, prop.name(), 0, true);
-        }
-
-        for (String txtIdx : meta.getTextFields()) {
-            PortableProperty prop = buildPortableProperty(txtIdx, String.class);
-
-            d.addProperty(key, prop, false);
-
-            d.addFieldToTextIndex(prop.name());
-        }
-
-        Map<String, LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>>> grps = meta.getGroups();
-
-        if (grps != null) {
-            for (Map.Entry<String, LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>>> entry : grps.entrySet()) {
-                String idxName = entry.getKey();
-
-                LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>> idxFields = entry.getValue();
-
-                int order = 0;
-
-                for (Map.Entry<String, IgniteBiTuple<Class<?>, Boolean>> idxField : idxFields.entrySet()) {
-                    PortableProperty prop = buildPortableProperty(idxField.getKey(), idxField.getValue().get1());
-
-                    d.addProperty(key, prop, false);
-
-                    Boolean descending = idxField.getValue().get2();
-
-                    d.addFieldToIndex(idxName, prop.name(), order, descending != null && descending);
-
-                    order++;
-                }
-            }
-        }
-
-        for (Map.Entry<String, Class<?>> entry : meta.getQueryFields().entrySet()) {
-            PortableProperty prop = buildPortableProperty(entry.getKey(), entry.getValue());
-
-            if (!d.props.containsKey(prop.name()))
-                d.addProperty(key, prop, false);
-        }
-    }
-
-    /**
-     * Builds portable object property.
-     *
-     * @param pathStr String representing path to the property. May contains dots '.' to identify
-     *      nested fields.
-     * @param resType Result type.
-     * @return Portable property.
-     */
-    static PortableProperty buildPortableProperty(String pathStr, Class<?> resType) {
-        String[] path = pathStr.split("\\.");
-
-        PortableProperty res = null;
-
-        for (String prop : path)
-            res = new PortableProperty(prop, res, resType);
-
-        return res;
-    }
-
-    /**
-     * @param cls Source type class.
-     * @param pathStr String representing path to the property. May contains dots '.' to identify nested fields.
-     * @param resType Expected result type.
-     * @return Property instance corresponding to the given path.
-     * @throws GridException If property cannot be created.
-     */
-    static ClassProperty buildClassProperty(Class<?> cls, String pathStr, Class<?> resType) throws GridException {
-        String[] path = pathStr.split("\\.");
-
-        ClassProperty res = null;
-
-        for (String prop : path) {
-            ClassProperty tmp;
-
-            try {
-                StringBuilder bld = new StringBuilder("get");
-
-                bld.append(prop);
-
-                bld.setCharAt(3, Character.toUpperCase(bld.charAt(3)));
-
-                tmp = new ClassProperty(cls.getMethod(bld.toString()));
-            }
-            catch (NoSuchMethodException ignore) {
-                try {
-                    tmp = new ClassProperty(cls.getDeclaredField(prop));
-                }
-                catch (NoSuchFieldException ignored) {
-                    throw new GridException("Failed to find getter method or field for property named " +
-                        "'" + prop + "': " + cls.getName());
-                }
-            }
-
-            tmp.parent(res);
-
-            cls = tmp.type();
-
-            res = tmp;
-        }
-
-        if (!U.box(resType).isAssignableFrom(U.box(res.type())))
-            throw new GridException("Failed to create property for given path (actual property type is not assignable" +
-                " to declared type [path=" + pathStr + ", actualType=" + res.type().getName() +
-                ", declaredType=" + resType.getName() + ']');
-
-        return res;
-    }
-
-    /**
-     * Gets types for space.
-     *
-     * @param space Space name.
-     * @return Descriptors.
-     */
-    public Collection<IndexingTypeDescriptor> types(@Nullable String space) {
-        Collection<IndexingTypeDescriptor> spaceTypes = new ArrayList<>(
-            Math.min(10, types.size()));
-
-        for (Map.Entry<TypeId, TypeDescriptor> e : types.entrySet()) {
-            TypeDescriptor desc = e.getValue();
-
-            if (desc.registered() && F.eq(e.getKey().space, space))
-                spaceTypes.add(desc);
-        }
-
-        return spaceTypes;
-    }
-
-    /**
-     * Gets type for space and type name.
-     *
-     * @param space Space name.
-     * @param typeName Type name.
-     * @return Type.
-     * @throws GridException If failed.
-     */
-    public IndexingTypeDescriptor type(@Nullable String space, String typeName) throws GridException {
-        TypeDescriptor type = typesByName.get(new TypeName(space, typeName));
-
-        if (type == null || !type.registered())
-            throw new GridException("Failed to find type descriptor for type name: " + typeName);
-
-        return type;
-    }
-
-    /**
-     * @param cls Field type.
-     * @return {@code True} if given type is a spatial geometry type based on {@code com.vividsolutions.jts} library.
-     * @throws GridException If failed.
-     */
-    private static boolean isGeometryClass(Class<?> cls) throws GridException {
-        Class<?> dataTypeCls;
-
-        try {
-            dataTypeCls = Class.forName("org.h2.value.DataType");
-        }
-        catch (ClassNotFoundException ignored) {
-            return false; // H2 is not in classpath.
-        }
-
-        try {
-            Method method = dataTypeCls.getMethod("isGeometryClass", Class.class);
-
-            return (Boolean)method.invoke(null, cls);
-        }
-        catch (Exception e) {
-            throw new GridException("Failed to invoke 'org.h2.value.DataType.isGeometryClass' method.", e);
-        }
-    }
-
-    /**
-     *
-     */
-    private abstract static class Property {
-        /**
-         * Gets this property value from the given object.
-         *
-         * @param x Object with this property.
-         * @return Property value.
-         * @throws org.apache.ignite.spi.IgniteSpiException If failed.
-         */
-        public abstract Object value(Object x) throws IgniteSpiException;
-
-        /**
-         * @return Property name.
-         */
-        public abstract String name();
-
-        /**
-         * @return Class member type.
-         */
-        public abstract Class<?> type();
-    }
-
-    /**
-     * Description of type property.
-     */
-    private static class ClassProperty extends Property {
-        /** */
-        private final Member member;
-
-        /** */
-        private ClassProperty parent;
-
-        /** */
-        private String name;
-
-        /** */
-        private boolean field;
-
-        /**
-         * Constructor.
-         *
-         * @param member Element.
-         */
-        ClassProperty(Member member) {
-            this.member = member;
-
-            name = member instanceof Method && member.getName().startsWith("get") && member.getName().length() > 3 ?
-                member.getName().substring(3) : member.getName();
-
-            ((AccessibleObject) member).setAccessible(true);
-
-            field = member instanceof Field;
-        }
-
-        /** {@inheritDoc} */
-        @Override public Object value(Object x) throws IgniteSpiException {
-            if (parent != null)
-                x = parent.value(x);
-
-            if (x == null)
-                return null;
-
-            try {
-                if (field) {
-                    Field field = (Field)member;
-
-                    return field.get(x);
-                }
-                else {
-                    Method mtd = (Method)member;
-
-                    return mtd.invoke(x);
-                }
-            }
-            catch (Exception e) {
-                throw new IgniteSpiException(e);
-            }
-        }
-
-        /**
-         * @param name Property name.
-         */
-        public void name(String name) {
-            this.name = name;
-        }
-
-        /** {@inheritDoc} */
-        @Override public String name() {
-            return name;
-        }
-
-        /** {@inheritDoc} */
-        @Override public Class<?> type() {
-            return member instanceof Field ? ((Field)member).getType() : ((Method)member).getReturnType();
-        }
-
-        /**
-         * @param parent Parent property if this is embeddable element.
-         */
-        public void parent(ClassProperty parent) {
-            this.parent = parent;
-        }
-
-        /** {@inheritDoc} */
-        @Override public String toString() {
-            return S.toString(ClassProperty.class, this);
-        }
-
-        /**
-         * @param cls Class.
-         * @return {@code true} If this property or some parent relates to member of the given class.
-         */
-        public boolean knowsClass(Class<?> cls) {
-            return member.getDeclaringClass() == cls || (parent != null && parent.knowsClass(cls));
-        }
-    }
-
-    /**
-     *
-     */
-    private static class PortableProperty extends Property {
-        /** Property name. */
-        private String propName;
-
-        /** Parent property. */
-        private PortableProperty parent;
-
-        /** Result class. */
-        private Class<?> type;
-
-        /**
-         * Constructor.
-         *
-         * @param propName Property name.
-         * @param parent Parent property.
-         * @param type Result type.
-         */
-        private PortableProperty(String propName, PortableProperty parent, Class<?> type) {
-            this.propName = propName;
-            this.parent = parent;
-            this.type = type;
-        }
-
-        /** {@inheritDoc} */
-        @Override public Object value(Object obj) throws IgniteSpiException {
-            if (parent != null)
-                obj = parent.value(obj);
-
-            if (obj == null)
-                return null;
-
-            if (!(obj instanceof PortableObject))
-                throw new IgniteSpiException("Non-portable object received as a result of property extraction " +
-                    "[parent=" + parent + ", propName=" + propName + ", obj=" + obj + ']');
-
-            try {
-                return ((PortableObject)obj).field(propName);
-            }
-            catch (PortableException e) {
-                throw new IgniteSpiException(e);
-            }
-        }
-
-        /** {@inheritDoc} */
-        @Override public String name() {
-            return propName;
-        }
-
-        /** {@inheritDoc} */
-        @Override public Class<?> type() {
-            return type;
-        }
-    }
-
-    /**
-     * Descriptor of type.
-     */
-    private static class TypeDescriptor implements IndexingTypeDescriptor {
-        /** */
-        private String name;
-
-        /** Value field names and types with preserved order. */
-        @GridToStringInclude
-        private final Map<String, Class<?>> valFields = new LinkedHashMap<>();
-
-        /** */
-        @GridToStringExclude
-        private final Map<String, Property> props = new HashMap<>();
-
-        /** Key field names and types with preserved order. */
-        @GridToStringInclude
-        private final Map<String, Class<?>> keyFields = new LinkedHashMap<>();
-
-        /** */
-        @GridToStringInclude
-        private final Map<String, IndexDescriptor> indexes = new HashMap<>();
-
-        /** */
-        private IndexDescriptor fullTextIdx;
-
-        /** */
-        private Class<?> keyCls;
-
-        /** */
-        private Class<?> valCls;
-
-        /** */
-        private boolean valTextIdx;
-
-        /** To ensure that type was registered in SPI and only once. */
-        private final GridAtomicInitializer<Void> initializer = new GridAtomicInitializer<>();
-
-        /** SPI can decide not to register this type. */
-        private boolean registered;
-
-        /**
-         * @param c Initialization callable.
-         * @throws GridException In case of error.
-         */
-        void init(Callable<Void> c) throws GridException {
-            initializer.init(c);
-        }
-
-        /**
-         * @return Waits for initialization.
-         * @throws GridInterruptedException If thread is interrupted.
-         */
-        boolean await() throws GridInterruptedException {
-            return initializer.await();
-        }
-
-        /**
-         * @return Whether initialization was successfully completed.
-         */
-        boolean succeeded() {
-            return initializer.succeeded();
-        }
-
-        /**
-         * @return {@code True} if type registration in SPI was finished and type was not rejected.
-         */
-        boolean registered() {
-            return initializer.succeeded() && registered;
-        }
-
-        /**
-         * @param registered Sets registered flag.
-         */
-        void registered(boolean registered) {
-            this.registered = registered;
-        }
-
-        /** {@inheritDoc} */
-        @Override public String name() {
-            return name;
-        }
-
-        /**
-         * Sets type name.
-         *
-         * @param name Name.
-         */
-        void name(String name) {
-            this.name = name;
-        }
-
-        /** {@inheritDoc} */
-        @Override public Map<String, Class<?>> valueFields() {
-            return valFields;
-        }
-
-        /** {@inheritDoc} */
-        @Override public Map<String, Class<?>> keyFields() {
-            return keyFields;
-        }
-
-        /** {@inheritDoc} */
-        @Override public <T> T value(Object obj, String field) throws IgniteSpiException {
-            assert obj != null;
-            assert field != null;
-
-            Property prop = props.get(field);
-
-            if (prop == null)
-                throw new IgniteSpiException("Failed to find field '" + field + "' in type '" + name + "'.");
-
-            return (T)prop.value(obj);
-        }
-
-        /** {@inheritDoc} */
-        @Override public Map<String, org.apache.ignite.spi.indexing.IndexDescriptor> indexes() {
-            return Collections.<String, org.apache.ignite.spi.indexing.IndexDescriptor>unmodifiableMap(indexes);
-        }
-
-        /**
-         * Adds index.
-         *
-         * @param idxName Index name.
-         * @param type Index type.
-         * @return Index descriptor.
-         * @throws GridException In case of error.
-         */
-        public IndexDescriptor addIndex(String idxName, IndexType type) throws GridException {
-            IndexDescriptor idx = new IndexDescriptor(type);
-
-            if (indexes.put(idxName, idx) != null)
-                throw new GridException("Index with name '" + idxName + "' already exists.");
-
-            return idx;
-        }
-
-        /**
-         * Adds field to index.
-         *
-         * @param idxName Index name.
-         * @param field Field name.
-         * @param orderNum Fields order number in index.
-         * @param descending Sorting order.
-         * @throws GridException If failed.
-         */
-        public void addFieldToIndex(String idxName, String field, int orderNum,
-            boolean descending) throws GridException {
-            IndexDescriptor desc = indexes.get(idxName);
-
-            if (desc == null)
-                desc = addIndex(idxName, SORTED);
-
-            desc.addField(field, orderNum, descending);
-        }
-
-        /**
-         * Adds field to text index.
-         *
-         * @param field Field name.
-         */
-        public void addFieldToTextIndex(String field) {
-            if (fullTextIdx == null) {
-                fullTextIdx = new IndexDescriptor(FULLTEXT);
-
-                indexes.put(null, fullTextIdx);
-            }
-
-            fullTextIdx.addField(field, 0, false);
-        }
-
-        /** {@inheritDoc} */
-        @Override public Class<?> valueClass() {
-            return valCls;
-        }
-
-        /**
-         * Sets value class.
-         *
-         * @param valCls Value class.
-         */
-        void valueClass(Class<?> valCls) {
-            this.valCls = valCls;
-        }
-
-        /** {@inheritDoc} */
-        @Override public Class<?> keyClass() {
-            return keyCls;
-        }
-
-        /**
-         * Set key class.
-         *
-         * @param keyCls Key class.
-         */
-        void keyClass(Class<?> keyCls) {
-            this.keyCls = keyCls;
-        }
-
-        /**
-         * Adds property to the type descriptor.
-         *
-         * @param key If given property relates to key.
-         * @param prop Property.
-         * @param failOnDuplicate Fail on duplicate flag.
-         * @throws GridException In case of error.
-         */
-        public void addProperty(boolean key, Property prop, boolean failOnDuplicate) throws GridException {
-            String name = prop.name();
-
-            if (props.put(name, prop) != null && failOnDuplicate)
-                throw new GridException("Property with name '" + name + "' already exists.");
-
-            if (key)
-                keyFields.put(name, prop.type());
-            else
-                valFields.put(name, prop.type());
-        }
-
-        /** {@inheritDoc} */
-        @Override public boolean valueTextIndex() {
-            return valTextIdx;
-        }
-
-        /**
-         * Sets if this value should be text indexed.
-         *
-         * @param valTextIdx Flag value.
-         */
-        public void valueTextIndex(boolean valTextIdx) {
-            this.valTextIdx = valTextIdx;
-        }
-
-        /** {@inheritDoc} */
-        @Override public String toString() {
-            return S.toString(TypeDescriptor.class, this);
-        }
-    }
-
-    /**
-     * Index descriptor.
-     */
-    private static class IndexDescriptor implements org.apache.ignite.spi.indexing.IndexDescriptor {
-        /** Fields sorted by order number. */
-        private final Collection<T2<String, Integer>> fields = new TreeSet<>(
-            new Comparator<T2<String, Integer>>() {
-                @Override public int compare(T2<String, Integer> o1, T2<String, Integer> o2) {
-                    if (o1.get2().equals(o2.get2())) // Order is equal, compare field names to avoid replace in Set.
-                        return o1.get1().compareTo(o2.get1());
-
-                    return o1.get2() < o2.get2() ? -1 : 1;
-                }
-            });
-
-        /** Fields which should be indexed in descending order. */
-        private Collection<String> descendings;
-
-        /** */
-        private final IndexType type;
-
-        /**
-         * @param type Type.
-         */
-        private IndexDescriptor(IndexType type) {
-            assert type != null;
-
-            this.type = type;
-        }
-
-        /** {@inheritDoc} */
-        @Override public Collection<String> fields() {
-            Collection<String> res = new ArrayList<>(fields.size());
-
-            for (T2<String, Integer> t : fields)
-                res.add(t.get1());
-
-            return res;
-        }
-
-        /** {@inheritDoc} */
-        @Override public boolean descending(String field) {
-            return descendings != null && descendings.contains(field);
-        }
-
-        /**
-         * Adds field to this index.
-         *
-         * @param field Field name.
-         * @param orderNum Field order number in this index.
-         * @param descending Sort order.
-         */
-        public void addField(String field, int orderNum, boolean descending) {
-            fields.add(new T2<>(field, orderNum));
-
-            if (descending) {
-                if (descendings == null)
-                    descendings  = new HashSet<>();
-
-                descendings.add(field);
-            }
-        }
-
-        /** {@inheritDoc} */
-        @Override public IndexType type() {
-            return type;
-        }
-
-        /** {@inheritDoc} */
-        @Override public String toString() {
-            return S.toString(IndexDescriptor.class, this);
-        }
-    }
-
-    /**
-     * Identifying TypeDescriptor by space and value class.
-     */
-    private static class TypeId {
-        /** */
-        private final String space;
-
-        /** Value type. */
-        private final Class<?> valType;
-
-        /** Value type ID. */
-        private final int valTypeId;
-
-        /**
-         * Constructor.
-         *
-         * @param space Space name.
-         * @param valType Value type.
-         */
-        private TypeId(String space, Class<?> valType) {
-            assert valType != null;
-
-            this.space = space;
-            this.valType = valType;
-
-            valTypeId = 0;
-        }
-
-        /**
-         * Constructor.
-         *
-         * @param space Space name.
-         * @param valTypeId Value type ID.
-         */
-        private TypeId(String space, int valTypeId) {
-            this.space = space;
-            this.valTypeId = valTypeId;
-
-            valType = null;
-        }
-
-        /** {@inheritDoc} */
-        @Override public boolean equals(Object o) {
-            if (this == o)
-                return true;
-
-            if (o == null || getClass() != o.getClass())
-                return false;
-
-            TypeId typeId = (TypeId)o;
-
-            return (valTypeId == typeId.valTypeId) &&
-                (valType != null ? valType == typeId.valType : typeId.valType == null) &&
-                (space != null ? space.equals(typeId.space) : typeId.space == null);
-        }
-
-        /** {@inheritDoc} */
-        @Override public int hashCode() {
-            return 31 * (space != null ? space.hashCode() : 0) + (valType != null ? valType.hashCode() : valTypeId);
-        }
-
-        /** {@inheritDoc} */
-        @Override public String toString() {
-            return S.toString(TypeId.class, this);
-        }
-    }
-
-    /**
-     *
-     */
-    private static class TypeName {
-       /** */
-       private final String space;
-
-       /** */
-       private final String typeName;
-
-       /**
-        * @param space Space name.
-        * @param typeName Type name.
-        */
-        private TypeName(@Nullable String space, String typeName) {
-            assert !F.isEmpty(typeName) : typeName;
-
-            this.space = space;
-            this.typeName = typeName;
-        }
-
-        /** {@inheritDoc} */
-        @Override public boolean equals(Object o) {
-            if (this == o)
-                return true;
-
-            if (o == null || getClass() != o.getClass())
-                return false;
-
-            TypeName other = (TypeName)o;
-
-            return (space != null ? space.equals(other.space) : other.space == null) &&
-                    typeName.equals(other.typeName);
-        }
-
-        /** {@inheritDoc} */
-        @Override public int hashCode() {
-            return 31 * (space != null ? space.hashCode() : 0) + typeName.hashCode();
-        }
-
-        /** {@inheritDoc} */
-        @Override public String toString() {
-            return S.toString(TypeName.class, this);
-        }
-    }
-
-    /**
-     * Indexing marshaller which also stores information about class loader and allows lazy unmarshalling.
-     */
-    private class IdxMarshaller implements IndexingMarshaller {
-        /** {@inheritDoc} */
-        @Override public <T> IndexingEntity<T> unmarshal(final byte[] bytes) {
-            long ldrId = bytes[0] == -1 ? 0 : U.bytesToLong(bytes, 0);
-
-            final ClassLoader ldr = ldrId == 0 ? null : ldrById.get(ldrId);
-
-            final int off = ldrId == 0 ? 1 : 8;
-
-            final int len = bytes.length - off;
-
-            return new IndexingEntity<T>() {
-                /** */
-                private T val;
-
-                /** */
-                private byte[] valBytes;
-
-                @Override public T value() throws IgniteSpiException {
-                    if (val == null) {
-                        try {
-                            val = marsh.unmarshal(new ByteArrayInputStream(bytes, off, len), ldr);
-                        }
-                        catch (GridException e) {
-                            throw new IgniteSpiException(e);
-                        }
-                    }
-
-                    return val;
-                }
-
-                @Override public byte[] bytes() {
-                    if (valBytes == null) {
-                        byte[] bs = new byte[len];
-
-                        U.arrayCopy(bytes, off, bs, 0, len);
-
-                        valBytes = bs;
-                    }
-
-                    return valBytes;
-                }
-
-                @Override public boolean hasValue() {
-                    return val != null;
-                }
-            };
-        }
-
-        /** {@inheritDoc} */
-        @Override public byte[] marshal(IndexingEntity<?> entity) throws IgniteSpiException {
-            Object val = entity.value();
-
-            ClassLoader ldr = val.getClass().getClassLoader();
-
-            byte[] bytes = entity.bytes();
-
-            ByteArrayOutputStream out = new ByteArrayOutputStream(bytes == null ? 128 : bytes.length + 8);
-
-            if (ldr == null)
-                // In special case of bootstrap class loader ldrId will be one byte -1.
-                out.write(-1);
-            else {
-                Long ldrId;
-
-                while ((ldrId = idByLdr.get(ldr)) == null) {
-                    ldrId = ldrIdGen.incrementAndGet();
-
-                    if (idByLdr.putIfAbsent(ldr, ldrId) == null) {
-                        ldrById.put(ldrId, ldr);
-
-                        break;
-                    }
-                }
-
-                try {
-                    out.write(U.longToBytes(ldrId));
-                }
-                catch (IOException e) {
-                    throw new IgniteSpiException(e);
-                }
-            }
-
-            try {
-                if (bytes == null)
-                    marsh.marshal(val, out);
-                else
-                    out.write(bytes);
-            }
-            catch (Exception e) {
-                throw new IgniteSpiException(e);
-            }
-
-            return out.toByteArray();
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/922a2bab/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheDistributedFieldsQueryFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheDistributedFieldsQueryFuture.java b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheDistributedFieldsQueryFuture.java
index 67d8393..6bf1f45 100644
--- a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheDistributedFieldsQueryFuture.java
+++ b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheDistributedFieldsQueryFuture.java
@@ -11,8 +11,8 @@ package org.gridgain.grid.kernal.processors.cache.query;
 
 import org.apache.ignite.cluster.*;
 import org.apache.ignite.lang.*;
-import org.apache.ignite.spi.indexing.*;
 import org.gridgain.grid.kernal.processors.cache.*;
+import org.gridgain.grid.kernal.processors.query.*;
 import org.gridgain.grid.util.future.*;
 import org.jetbrains.annotations.*;
 
@@ -29,7 +29,7 @@ public class GridCacheDistributedFieldsQueryFuture
     private static final long serialVersionUID = 0L;
 
     /** Meta data future. */
-    private final GridFutureAdapter<List<IndexingFieldMetadata>> metaFut;
+    private final GridFutureAdapter<List<GridQueryFieldMetadata>> metaFut;
 
     /**
      * Required by {@link Externalizable}.
@@ -61,7 +61,7 @@ public class GridCacheDistributedFieldsQueryFuture
      * @param err Error.
      * @param finished Finished or not.
      */
-    public void onPage(@Nullable UUID nodeId, @Nullable List<IndexingFieldMetadata> metaData,
+    public void onPage(@Nullable UUID nodeId, @Nullable List<GridQueryFieldMetadata> metaData,
         @Nullable Collection<Map<String, Object>> data, @Nullable Throwable err, boolean finished) {
         if (!metaFut.isDone() && metaData != null)
             metaFut.onDone(metaData);
@@ -86,7 +86,7 @@ public class GridCacheDistributedFieldsQueryFuture
     }
 
     /** {@inheritDoc} */
-    @Override public IgniteFuture<List<IndexingFieldMetadata>> metadata() {
+    @Override public IgniteFuture<List<GridQueryFieldMetadata>> metadata() {
         return metaFut;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/922a2bab/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheDistributedQueryManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheDistributedQueryManager.java b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheDistributedQueryManager.java
index ebbfa6c..9306eb3 100644
--- a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheDistributedQueryManager.java
+++ b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheDistributedQueryManager.java
@@ -12,11 +12,11 @@ package org.gridgain.grid.kernal.processors.cache.query;
 import org.apache.ignite.cluster.*;
 import org.apache.ignite.events.*;
 import org.apache.ignite.lang.*;
-import org.apache.ignite.spi.indexing.*;
 import org.gridgain.grid.*;
 import org.gridgain.grid.cache.*;
 import org.gridgain.grid.cache.query.*;
 import org.gridgain.grid.kernal.managers.eventstorage.*;
+import org.gridgain.grid.kernal.processors.query.*;
 import org.gridgain.grid.util.*;
 import org.gridgain.grid.util.typedef.*;
 import org.gridgain.grid.util.typedef.internal.*;
@@ -432,8 +432,8 @@ public class GridCacheDistributedQueryManager<K, V> extends GridCacheQueryManage
 
     /** {@inheritDoc} */
     @Override protected boolean onFieldsPageReady(boolean loc, GridCacheQueryInfo qryInfo,
-        @Nullable List<IndexingFieldMetadata> metadata,
-        @Nullable Collection<List<IndexingEntity<?>>> entities,
+        @Nullable List<GridQueryFieldMetadata> metadata,
+        @Nullable Collection<?> entities,
         @Nullable Collection<?> data,
         boolean finished, @Nullable Throwable e) {
         assert qryInfo != null;

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/922a2bab/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheFieldsQueryErrorFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheFieldsQueryErrorFuture.java b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheFieldsQueryErrorFuture.java
index 9834ff8..3da96d7 100644
--- a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheFieldsQueryErrorFuture.java
+++ b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheFieldsQueryErrorFuture.java
@@ -10,8 +10,8 @@
 package org.gridgain.grid.kernal.processors.cache.query;
 
 import org.apache.ignite.lang.*;
-import org.apache.ignite.spi.indexing.*;
 import org.gridgain.grid.kernal.*;
+import org.gridgain.grid.kernal.processors.query.*;
 import org.gridgain.grid.util.future.*;
 
 import java.util.*;
@@ -40,7 +40,7 @@ public class GridCacheFieldsQueryErrorFuture extends GridCacheQueryErrorFuture<L
     /**
      * @return Metadata.
      */
-    public IgniteFuture<List<IndexingFieldMetadata>> metadata() {
-        return new GridFinishedFuture<>(ctx, incMeta ? Collections.<IndexingFieldMetadata>emptyList() : null);
+    public IgniteFuture<List<GridQueryFieldMetadata>> metadata() {
+        return new GridFinishedFuture<>(ctx, incMeta ? Collections.<GridQueryFieldMetadata>emptyList() : null);
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/922a2bab/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheLocalFieldsQueryFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheLocalFieldsQueryFuture.java b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheLocalFieldsQueryFuture.java
index cc8ed19..5114f3a 100644
--- a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheLocalFieldsQueryFuture.java
+++ b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheLocalFieldsQueryFuture.java
@@ -10,8 +10,8 @@
 package org.gridgain.grid.kernal.processors.cache.query;
 
 import org.apache.ignite.lang.*;
-import org.apache.ignite.spi.indexing.*;
 import org.gridgain.grid.kernal.processors.cache.*;
+import org.gridgain.grid.kernal.processors.query.*;
 import org.gridgain.grid.util.future.*;
 import org.jetbrains.annotations.*;
 
@@ -28,7 +28,7 @@ public class GridCacheLocalFieldsQueryFuture
     private static final long serialVersionUID = 0L;
 
     /** Meta data future. */
-    private final GridFutureAdapter<List<IndexingFieldMetadata>> metaFut;
+    private final GridFutureAdapter<List<GridQueryFieldMetadata>> metaFut;
 
     /**
      * Required by {@link Externalizable}.
@@ -57,7 +57,7 @@ public class GridCacheLocalFieldsQueryFuture
      * @param err Error.
      * @param finished Finished or not.
      */
-    public void onPage(@Nullable UUID nodeId, @Nullable List<IndexingFieldMetadata> metaData,
+    public void onPage(@Nullable UUID nodeId, @Nullable List<GridQueryFieldMetadata> metaData,
         @Nullable Collection<?> data, @Nullable Throwable err, boolean finished) {
         onPage(nodeId, data, err, finished);
 
@@ -66,7 +66,7 @@ public class GridCacheLocalFieldsQueryFuture
     }
 
     /** {@inheritDoc} */
-    @Override public IgniteFuture<List<IndexingFieldMetadata>> metadata() {
+    @Override public IgniteFuture<List<GridQueryFieldMetadata>> metadata() {
         return metaFut;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/922a2bab/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheLocalQueryManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheLocalQueryManager.java b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheLocalQueryManager.java
index 85cab07..9dd1d7f 100644
--- a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheLocalQueryManager.java
+++ b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheLocalQueryManager.java
@@ -10,9 +10,9 @@
 package org.gridgain.grid.kernal.processors.cache.query;
 
 import org.apache.ignite.cluster.*;
-import org.apache.ignite.spi.indexing.*;
 import org.gridgain.grid.*;
 import org.gridgain.grid.cache.query.*;
+import org.gridgain.grid.kernal.processors.query.*;
 import org.jetbrains.annotations.*;
 
 import java.util.*;
@@ -45,8 +45,8 @@ public class GridCacheLocalQueryManager<K, V> extends GridCacheQueryManager<K, V
     /** {@inheritDoc} */
     @Override protected boolean onFieldsPageReady(boolean loc,
         GridCacheQueryInfo qryInfo,
-        @Nullable List<IndexingFieldMetadata> metaData,
-        @Nullable Collection<List<IndexingEntity<?>>> entities,
+        @Nullable List<GridQueryFieldMetadata> metaData,
+        @Nullable Collection<?> entities,
         @Nullable Collection<?> data,
         boolean finished,
         @Nullable Throwable e) {

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/922a2bab/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesEx.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesEx.java b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesEx.java
index a3fd1c8..803719c 100644
--- a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesEx.java
+++ b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesEx.java
@@ -34,4 +34,11 @@ public interface GridCacheQueriesEx<K, V> extends GridCacheQueries<K, V> {
      * @return Created query.
      */
     public GridCacheQuery<List<?>> createSqlFieldsQuery(String qry, boolean incMeta);
+
+    /**
+     * Creates SPI query.
+     *
+     * @return Query.
+     */
+    public <R> GridCacheQuery<R> createSpiQuery();
 }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/922a2bab/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesImpl.java b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesImpl.java
index 98ff5e8..ee02797 100644
--- a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesImpl.java
+++ b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesImpl.java
@@ -10,6 +10,7 @@
 package org.gridgain.grid.kernal.processors.cache.query;
 
 import org.apache.ignite.lang.*;
+import org.apache.ignite.spi.indexing.*;
 import org.gridgain.grid.*;
 import org.gridgain.grid.cache.*;
 import org.gridgain.grid.cache.query.*;
@@ -61,7 +62,7 @@ public class GridCacheQueriesImpl<K, V> implements GridCacheQueriesEx<K, V>, Ext
         return new GridCacheQueryAdapter<>(ctx,
             SQL,
             filter(),
-            ctx.kernalContext().indexing().typeName(U.box(cls)),
+            ctx.kernalContext().query().typeName(U.box(cls)),
             clause,
             null,
             false,
@@ -105,7 +106,7 @@ public class GridCacheQueriesImpl<K, V> implements GridCacheQueriesEx<K, V>, Ext
         return new GridCacheQueryAdapter<>(ctx,
             TEXT,
             filter(),
-            ctx.kernalContext().indexing().typeName(U.box(cls)),
+            ctx.kernalContext().query().typeName(U.box(cls)),
             search,
             null,
             false,
@@ -140,6 +141,22 @@ public class GridCacheQueriesImpl<K, V> implements GridCacheQueriesEx<K, V>, Ext
             prj != null && prj.isKeepPortable());
     }
 
+    /**
+     * Query for {@link GridIndexingSpi}.
+     *
+     * @return Query.
+     */
+    public <R> GridCacheQuery<R> createSpiQuery() {
+        return new GridCacheQueryAdapter<>(ctx,
+            SPI,
+            filter(),
+            null,
+            null,
+            null,
+            false,
+            prj != null && prj.isKeepPortable());
+    }
+
     /** {@inheritDoc} */
     @Override public GridCacheContinuousQuery<K, V> createContinuousQuery() {
         return ctx.continuousQueries().createQuery(prj == null ? null : prj.predicate());

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/922a2bab/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesProxy.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesProxy.java b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesProxy.java
index d9d40e4..03f1f03 100644
--- a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesProxy.java
+++ b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueriesProxy.java
@@ -154,6 +154,18 @@ public class GridCacheQueriesProxy<K, V> implements GridCacheQueriesEx<K, V>, Ex
     }
 
     /** {@inheritDoc} */
+    @Override public <R> GridCacheQuery<R> createSpiQuery() {
+        GridCacheProjectionImpl<K, V> prev = gate.enter(prj);
+
+        try {
+            return delegate.createSpiQuery();
+        }
+        finally {
+            gate.leave(prev);
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public IgniteFuture<?> rebuildIndexes(Class<?> cls) {
         GridCacheProjectionImpl<K, V> prev = gate.enter(prj);
 

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/922a2bab/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueryAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueryAdapter.java b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueryAdapter.java
index 470ed24..dbddd02 100644
--- a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueryAdapter.java
+++ b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/query/GridCacheQueryAdapter.java
@@ -12,11 +12,11 @@ package org.gridgain.grid.kernal.processors.cache.query;
 import org.apache.ignite.*;
 import org.apache.ignite.cluster.*;
 import org.apache.ignite.lang.*;
+import org.apache.ignite.plugin.security.*;
 import org.gridgain.grid.*;
 import org.gridgain.grid.cache.*;
 import org.gridgain.grid.cache.query.*;
 import org.gridgain.grid.kernal.processors.cache.*;
-import org.apache.ignite.plugin.security.*;
 import org.gridgain.grid.util.typedef.*;
 import org.gridgain.grid.util.typedef.internal.*;
 import org.jetbrains.annotations.*;
@@ -436,7 +436,7 @@ public class GridCacheQueryAdapter<T> implements GridCacheQuery<T> {
 
         boolean loc = nodes.size() == 1 && F.first(nodes).id().equals(cctx.localNodeId());
 
-        if (type == SQL_FIELDS)
+        if (type == SQL_FIELDS || type == SPI)
             return (GridCacheQueryFuture<R>)(loc ? qryMgr.queryFieldsLocal(bean) :
                 qryMgr.queryFieldsDistributed(bean, nodes));
         else