Repository: incubator-ignite Updated Branches: refs/heads/ignite-959 [created] b295f91a8
ignite-959 Avoid sending key-value class definitions to servers when starting a cache Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/b295f91a Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/b295f91a Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/b295f91a Branch: refs/heads/ignite-959 Commit: b295f91a8609af22f487b8c89851da8267aa40e5 Parents: 285d790 Author: agura <ag...@gridgain.com> Authored: Tue Jun 23 22:54:39 2015 +0300 Committer: agura <ag...@gridgain.com> Committed: Tue Jun 23 22:54:39 2015 +0300 ---------------------------------------------------------------------- .../apache/ignite/cache/CacheTypeMetadata.java | 30 ++ .../processors/query/GridQueryProcessor.java | 313 ++++++++++++++++--- .../CacheMetricsForClusterGroupSelfTest.java | 2 +- .../processors/query/h2/IgniteH2Indexing.java | 2 + 4 files changed, 294 insertions(+), 53 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/b295f91a/modules/core/src/main/java/org/apache/ignite/cache/CacheTypeMetadata.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/CacheTypeMetadata.java b/modules/core/src/main/java/org/apache/ignite/cache/CacheTypeMetadata.java index 20129b7..d6b0c79 100644 --- a/modules/core/src/main/java/org/apache/ignite/cache/CacheTypeMetadata.java +++ b/modules/core/src/main/java/org/apache/ignite/cache/CacheTypeMetadata.java @@ -71,6 +71,10 @@ public class CacheTypeMetadata implements Serializable { @GridToStringInclude private Map<String, LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>>> grps; + /** Aliases for fields. */ + @GridToStringInclude + private Map<String, String> aliases; + /** * Default constructor. */ @@ -88,6 +92,8 @@ public class CacheTypeMetadata implements Serializable { txtFlds = new LinkedHashSet<>(); grps = new LinkedHashMap<>(); + + aliases = new HashMap<>(); } /** @@ -115,6 +121,8 @@ public class CacheTypeMetadata implements Serializable { txtFlds = new LinkedHashSet<>(src.getTextFields()); grps = new LinkedHashMap<>(src.getGroups()); + + aliases = new HashMap<>(src.aliases); } /** @@ -333,6 +341,28 @@ public class CacheTypeMetadata implements Serializable { this.grps = grps; } + /** + * Returns fields aliases. + * + * @return fields aliases. + */ + public Map<String, String> getAliases() { + return aliases; + } + + /** + * Adds field alias. + * + * @param alias Alias. + * @param fieldName Field name. + */ + public void addAlias(String alias, String fieldName) { + A.notNull(alias, "alias"); + A.notNull(fieldName, "fieldName"); + + aliases.put(alias, fieldName); + } + /** {@inheritDoc} */ @Override public String toString() { return S.toString(CacheTypeMetadata.class, this); http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/b295f91a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java index e080c6d..1b7edac 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java @@ -121,63 +121,238 @@ public class GridQueryProcessor extends GridProcessorAdapter { idx.registerCache(ccfg); try { - if (!F.isEmpty(ccfg.getTypeMetadata())) { - for (CacheTypeMetadata meta : ccfg.getTypeMetadata()) { - if (F.isEmpty(meta.getValueType())) - throw new IgniteCheckedException("Value type is not set: " + meta); + if (!F.isEmpty(ccfg.getTypeMetadata())) + processTypeMetadata(ccfg); + else { + Class<?>[] clss = ccfg.getIndexedTypes(); + + if (!F.isEmpty(clss)) { +// processIndexedTypes(ccfg, clss); + + Collection<CacheTypeMetadata> meta = generateTypeMetadata(clss); + + ccfg.setTypeMetadata(meta); + + processTypeMetadata(ccfg); + } + } + } + catch (IgniteCheckedException | RuntimeException e) { + idx.unregisterCache(ccfg); + + throw e; + } + } + + /** + * @param clss Classes. + */ + private Collection<CacheTypeMetadata> generateTypeMetadata(Class<?>[] clss) throws IgniteCheckedException { + List<CacheTypeMetadata> metadata = new ArrayList<>(clss.length / 2); + + for (int i = 0; i < clss.length; i += 2) { + Class<?> keyCls = clss[i]; + Class<?> valCls = clss[i + 1]; + + CacheTypeMetadata meta = new CacheTypeMetadata(); + + meta.setKeyType(keyCls); + meta.setValueType(valCls); + + processClassAnnotations(keyCls, meta, null); + processClassAnnotations(valCls, meta, null); + + metadata.add(meta); + } + + return metadata; + } + + /** + * @param cls Class. + * @param meta Type metadata. + * @param parentField Parent field name. + */ + private void processClassAnnotations(Class<?> cls, CacheTypeMetadata meta, String parentField) + throws IgniteCheckedException { + if (U.isJdk(cls) || idx.isGeometryClass(cls)) + return; - TypeDescriptor desc = new TypeDescriptor(); + for (Class<?> c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) { + for (Field field : c.getDeclaredFields()) { + QueryTextField txtAnn = field.getAnnotation(QueryTextField.class); + + if (txtAnn != null) { + String fieldName = parentField == null ? field.getName() : parentField + '.' + field.getName(); - Class<?> valCls = U.classForName(meta.getValueType(), null); + meta.getTextFields().add(fieldName); + + meta.getQueryFields().put(fieldName, field.getType()); + } + + QuerySqlField sqlAnn = field.getAnnotation(QuerySqlField.class); - desc.name(valCls != null ? typeName(valCls) : meta.getValueType()); + if (sqlAnn != null) { + String name = sqlAnn.name().isEmpty() ? field.getName() : sqlAnn.name(); - desc.valueClass(valCls != null ? valCls : Object.class); - desc.keyClass( - meta.getKeyType() == null ? - Object.class : - U.classForName(meta.getKeyType(), Object.class)); + String pathStr = parentField == null ? name : parentField + '.' + name; - TypeId typeId; + processClassAnnotations(field.getType(), meta, pathStr); - if (valCls == null || ctx.cacheObjects().isPortableEnabled()) { - processPortableMeta(meta, desc); + if (sqlAnn.index()) { + Map<String, Class<?>> fields = + sqlAnn.descending() ? meta.getDescendingFields() : meta.getAscendingFields(); - typeId = new TypeId(ccfg.getName(), ctx.cacheObjects().typeId(meta.getValueType())); + fields.put(pathStr, field.getType()); } - else { - processClassMeta(meta, desc); - typeId = new TypeId(ccfg.getName(), valCls); + meta.getQueryFields().put(pathStr, field.getType()); + + if (!sqlAnn.name().isEmpty()) + meta.addAlias(sqlAnn.name(), field.getName()); + + if (!F.isEmpty(sqlAnn.groups())) { + for (String grp : sqlAnn.groups()) { + LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>> fields = meta.getGroups().get(grp); + + if (fields == null) { + fields = new LinkedHashMap<>(); + + meta.getGroups().put(grp, fields); + } + + if (fields.put(pathStr, new IgniteBiTuple<Class<?>, Boolean>(field.getType(), false)) != null) + throw new IgniteCheckedException("Field " + pathStr + " already exists in group " + grp); + } } - addTypeByName(ccfg, desc); - types.put(typeId, desc); +/* + if (!F.isEmpty(sqlAnn.orderedGroups())) { + for (QuerySqlField.Group idx : sqlAnn.orderedGroups()) + desc.addFieldToIndex(idx.name(), prop.name(), idx.order(), idx.descending()); + } +*/ - desc.registered(idx.registerType(ccfg.getName(), desc)); } } - Class<?>[] clss = ccfg.getIndexedTypes(); + for (Method mtd : c.getDeclaredMethods()) { + String mtdName = mtd.getName().startsWith("get") && mtd.getName().length() > 3 ? + mtd.getName().substring(3) : mtd.getName(); + + QuerySqlField sqlAnn = mtd.getAnnotation(QuerySqlField.class); + QueryTextField txtAnn = mtd.getAnnotation(QueryTextField.class); + + if (sqlAnn != null || txtAnn != null) { + if (mtd.getParameterTypes().length != 0) + throw new IgniteCheckedException("Getter with QuerySqlField " + + "annotation cannot have parameters: " + mtd); + + Class<?> type = mtd.getReturnType(); + + if (txtAnn != null) { + String pathStr = parentField == null ? mtdName : parentField + '.' + mtdName; + + meta.getTextFields().add(pathStr); + + meta.getQueryFields().put(pathStr, type); + } + + if (sqlAnn != null) { + String name = sqlAnn.name().isEmpty() ? mtdName : sqlAnn.name(); + + name = parentField == null ? name : parentField + '.' + name; + + processClassAnnotations(mtd.getReturnType(), meta, name); + + if (sqlAnn.index()) { + Map<String, Class<?>> fields = + sqlAnn.descending() ? meta.getDescendingFields() : meta.getAscendingFields(); + + fields.put(name, type); + } + + meta.getQueryFields().put(name, type); + + if (!sqlAnn.name().isEmpty()) + meta.addAlias(sqlAnn.name(), mtdName); - if (!F.isEmpty(clss)) { - for (int i = 0; i < clss.length; i += 2) { - Class<?> keyCls = clss[i]; - Class<?> valCls = clss[i + 1]; + if (!F.isEmpty(sqlAnn.groups())) { + for (String grp : sqlAnn.groups()) { + LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>> fields = meta.getGroups().get(grp); - TypeDescriptor desc = processKeyAndValueClasses(keyCls, valCls); + if (fields == null) { + fields = new LinkedHashMap<>(); - addTypeByName(ccfg, desc); - types.put(new TypeId(ccfg.getName(), valCls), desc); + meta.getGroups().put(grp, fields); + } - desc.registered(idx.registerType(ccfg.getName(), desc)); + if (fields.put(name, new IgniteBiTuple<Class<?>, Boolean>(mtd.getReturnType(), false)) != null) + throw new IgniteCheckedException("Field " + name + " already exists in group " + grp); + } + } + } } } } - catch (IgniteCheckedException | RuntimeException e) { - idx.unregisterCache(ccfg); + } - throw e; + private void processIndexedTypes(CacheConfiguration<?, ?> ccfg, Class<?>[] clss) throws IgniteCheckedException { + for (int i = 0; i < clss.length; i += 2) { + Class<?> keyCls = clss[i]; + Class<?> valCls = clss[i + 1]; + + TypeDescriptor desc = processKeyAndValueClasses(keyCls, valCls); + + addTypeByName(ccfg, desc); + types.put(new TypeId(ccfg.getName(), valCls), desc); + + desc.registered(idx.registerType(ccfg.getName(), desc)); + } + } + + private void processTypeMetadata(CacheConfiguration<?, ?> ccfg) throws IgniteCheckedException { + for (CacheTypeMetadata meta : ccfg.getTypeMetadata()) { + if (F.isEmpty(meta.getValueType())) + throw new IgniteCheckedException("Value type is not set: " + meta); + + TypeDescriptor desc = new TypeDescriptor(); + + Class<?> valCls = U.classForName(meta.getValueType(), null); + + desc.name(valCls != null ? typeName(valCls) : meta.getValueType()); + + desc.valueClass(valCls != null ? valCls : Object.class); + desc.keyClass( + meta.getKeyType() == null ? + Object.class : + U.classForName(meta.getKeyType(), Object.class)); + + TypeId typeId; + + if (valCls == null || ctx.cacheObjects().isPortableEnabled()) { + processPortableMeta(meta, desc); + + typeId = new TypeId(ccfg.getName(), ctx.cacheObjects().typeId(meta.getValueType())); + } + else { + processClassMeta(meta, desc); + + typeId = new TypeId(ccfg.getName(), valCls); + + if ((U.isJdk(valCls) || idx.isGeometryClass(valCls)) && idx.isSqlType(valCls)) { // We have to index primitive _val. + String idxName = "_val_idx"; + + desc.addIndex(idxName, idx.isGeometryClass(valCls) ? GEO_SPATIAL : SORTED); + + desc.addFieldToIndex(idxName, "_VAL", 0, false); + } + } + + addTypeByName(ccfg, desc); + types.put(typeId, desc); + + desc.registered(idx.registerType(ccfg.getName(), desc)); } } @@ -1144,12 +1319,26 @@ public class GridQueryProcessor extends GridProcessorAdapter { assert keyCls != null; assert valCls != null; - for (Map.Entry<String, Class<?>> entry : meta.getAscendingFields().entrySet()) { + for (Map.Entry<String, Class<?>> entry : meta.getQueryFields().entrySet()) { ClassProperty prop = buildClassProperty( keyCls, valCls, entry.getKey(), - entry.getValue()); + entry.getValue(), + meta.getAliases()); + + d.addProperty(prop, false); + } + + for (Map.Entry<String, Class<?>> entry : meta.getAscendingFields().entrySet()) { + String name = entry.getKey(); + + ClassProperty prop = buildClassProperty( + keyCls, + valCls, + name, + entry.getValue(), + meta.getAliases()); d.addProperty(prop, false); @@ -1165,7 +1354,8 @@ public class GridQueryProcessor extends GridProcessorAdapter { keyCls, valCls, entry.getKey(), - entry.getValue()); + entry.getValue(), + meta.getAliases()); d.addProperty(prop, false); @@ -1181,7 +1371,8 @@ public class GridQueryProcessor extends GridProcessorAdapter { keyCls, valCls, txtIdx, - String.class); + String.class, + meta.getAliases()); d.addProperty(prop, false); @@ -1203,7 +1394,8 @@ public class GridQueryProcessor extends GridProcessorAdapter { keyCls, valCls, idxField.getKey(), - idxField.getValue().get1()); + idxField.getValue().get1(), + meta.getAliases()); d.addProperty(prop, false); @@ -1215,16 +1407,25 @@ public class GridQueryProcessor extends GridProcessorAdapter { } } } + } - for (Map.Entry<String, Class<?>> entry : meta.getQueryFields().entrySet()) { - ClassProperty prop = buildClassProperty( - keyCls, - valCls, - entry.getKey(), - entry.getValue()); + private String resolveAliases(String key, CacheTypeMetadata meta) { + Map<String, String> aliases = meta.getAliases(); - d.addProperty(prop, false); + String[] tokens = key.split("\\."); + + StringBuilder sb = new StringBuilder(); + + for (String token : tokens) { + String name = aliases.get(token); + + if (sb.length() > 0) + sb.append('.'); + + sb.append(name == null ? token : name); } + + return sb.toString(); } /** @@ -1327,16 +1528,17 @@ public class GridQueryProcessor extends GridProcessorAdapter { * @return Class property. * @throws IgniteCheckedException If failed. */ - private static ClassProperty buildClassProperty(Class<?> keyCls, Class<?> valCls, String pathStr, Class<?> resType) + private static ClassProperty buildClassProperty(Class<?> keyCls, Class<?> valCls, String pathStr, Class<?> resType, Map<String, String> aliases) throws IgniteCheckedException { ClassProperty res = buildClassProperty( true, keyCls, pathStr, - resType); + resType, + aliases); if (res == null) // We check key before value consistently with PortableProperty. - res = buildClassProperty(false, valCls, pathStr, resType); + res = buildClassProperty(false, valCls, pathStr, resType, aliases); if (res == null) throw new IgniteCheckedException("Failed to initialize property '" + pathStr + "' for " + @@ -1354,7 +1556,7 @@ public class GridQueryProcessor extends GridProcessorAdapter { * @return Property instance corresponding to the given path. * @throws IgniteCheckedException If property cannot be created. */ - static ClassProperty buildClassProperty(boolean key, Class<?> cls, String pathStr, Class<?> resType) + static ClassProperty buildClassProperty(boolean key, Class<?> cls, String pathStr, Class<?> resType, Map<String, String> aliases) throws IgniteCheckedException { String[] path = pathStr.split("\\."); @@ -1363,10 +1565,15 @@ public class GridQueryProcessor extends GridProcessorAdapter { for (String prop : path) { ClassProperty tmp; + String fieldName = aliases.get(prop); + + if (fieldName == null) + fieldName = prop; + try { StringBuilder bld = new StringBuilder("get"); - bld.append(prop); + bld.append(fieldName); bld.setCharAt(3, Character.toUpperCase(bld.charAt(3))); @@ -1374,13 +1581,15 @@ public class GridQueryProcessor extends GridProcessorAdapter { } catch (NoSuchMethodException ignore) { try { - tmp = new ClassProperty(cls.getDeclaredField(prop), key); + tmp = new ClassProperty(cls.getDeclaredField(fieldName), key); } catch (NoSuchFieldException ignored) { return null; } } + tmp.name(prop); + tmp.parent(res); cls = tmp.type(); http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/b295f91a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsForClusterGroupSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsForClusterGroupSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsForClusterGroupSelfTest.java index 1ba24e3..455e306 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsForClusterGroupSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsForClusterGroupSelfTest.java @@ -99,7 +99,7 @@ public class CacheMetricsForClusterGroupSelfTest extends GridCommonAbstractTest Collection<ClusterNode> nodes = grid(0).cluster().forRemotes().nodes(); for (ClusterNode node : nodes) { - Map<Integer, CacheMetrics> metrics = ((TcpDiscoveryNode) node).cacheMetrics(); + Map<Integer, CacheMetrics> metrics = ((TcpDiscoveryNode)node).cacheMetrics(); assertNotNull(metrics); assertFalse(metrics.isEmpty()); } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/b295f91a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 06c0961..138a15a 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -632,6 +632,8 @@ public class IgniteH2Indexing implements GridQueryIndexing { PreparedStatement stmt; try { +// System.out.println("!!! SQL: " + sql); + stmt = conn.prepareStatement(sql); } catch (SQLException e) {