IGNITE-1753 WIP on hashing.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/d5355def Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/d5355def Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/d5355def Branch: refs/heads/ignite-1753-1282 Commit: d5355def68e5910251fd6083c1858dc19f712a88 Parents: 6c9c113 Author: Alexey Kuznetsov <akuznet...@apache.org> Authored: Thu Oct 29 18:12:04 2015 +0700 Committer: Alexey Kuznetsov <akuznet...@apache.org> Committed: Thu Oct 29 18:12:04 2015 +0700 ---------------------------------------------------------------------- .../store/jdbc/CacheAbstractJdbcStore.java | 39 ++++++++++++---- .../cache/store/jdbc/CacheJdbcPojoStore.java | 49 +++++++++++--------- .../jdbc/CacheJdbcPojoStoreConfiguration.java | 26 +++++++++++ .../ignite/cache/store/jdbc/JdbcType.java | 3 ++ .../store/jdbc/JdbcTypeDefaultHashBuilder.java | 23 +++++++++ .../jdbc/JdbcTypeDefaultHashBuilderFactory.java | 19 ++++++++ .../cache/store/jdbc/JdbcTypeHashBuilder.java | 38 +++++++++++++++ 7 files changed, 167 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/d5355def/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheAbstractJdbcStore.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheAbstractJdbcStore.java b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheAbstractJdbcStore.java index 9a4ce75..c43a030 100644 --- a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheAbstractJdbcStore.java +++ b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheAbstractJdbcStore.java @@ -42,6 +42,7 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import javax.cache.Cache; import javax.cache.CacheException; +import javax.cache.configuration.Factory; import javax.cache.integration.CacheLoaderException; import javax.cache.integration.CacheWriterException; import javax.sql.DataSource; @@ -191,6 +192,9 @@ public abstract class CacheAbstractJdbcStore<K, V> implements CacheStore<K, V>, /** Types that store could process. */ private JdbcType[] types; + /** Factory for. */ + protected Factory<JdbcTypeHashBuilder> hashBuilderFactory = JdbcTypeDefaultHashBuilderFactory.INSTANCE; + /** * Get field value from object for use as query parameter. * @@ -212,12 +216,13 @@ public abstract class CacheAbstractJdbcStore<K, V> implements CacheStore<K, V>, * @param typeName Type name. * @param fields Fields descriptors. * @param loadColIdxs Select query columns index. + * @param key {@code true} * @param rs ResultSet. * @return Constructed object. * @throws CacheLoaderException If failed to construct cache object. */ protected abstract <R> R buildObject(@Nullable String cacheName, String typeName, - JdbcTypeField[] fields, Map<String, Integer> loadColIdxs, ResultSet rs) + JdbcTypeField[] fields, Map<String, Integer> loadColIdxs, boolean key, ResultSet rs) throws CacheLoaderException; /** @@ -520,8 +525,8 @@ public abstract class CacheAbstractJdbcStore<K, V> implements CacheStore<K, V>, ResultSet rs = stmt.executeQuery(); while (rs.next()) { - K key = buildObject(em.cacheName, em.keyType(), em.keyColumns(), em.loadColIdxs, rs); - V val = buildObject(em.cacheName, em.valueType(), em.valueColumns(), em.loadColIdxs, rs); + K key = buildObject(em.cacheName, em.keyType(), em.keyColumns(), em.loadColIdxs, true, rs); + V val = buildObject(em.cacheName, em.valueType(), em.valueColumns(), em.loadColIdxs, false, rs); clo.apply(key, val); } @@ -910,7 +915,7 @@ public abstract class CacheAbstractJdbcStore<K, V> implements CacheStore<K, V>, ResultSet rs = stmt.executeQuery(); if (rs.next()) - return buildObject(em.cacheName, em.valueType(), em.valueColumns(), em.loadColIdxs, rs); + return buildObject(em.cacheName, em.valueType(), em.valueColumns(), em.loadColIdxs, false, rs); } catch (SQLException e) { throw new CacheLoaderException("Failed to load object [table=" + em.fullTableName() + @@ -1578,6 +1583,24 @@ public abstract class CacheAbstractJdbcStore<K, V> implements CacheStore<K, V>, } /** + * Gets hash builder factory. + * + * @return Hash builder factory. + */ + public Factory<JdbcTypeHashBuilder> getHashBuilderFactory() { + return hashBuilderFactory; + } + + /** + * Sets hash builder factory.. + * + * @param hashBuilderFactory Hash builder factory. + */ + public void setHashBuilderFactory(Factory<JdbcTypeHashBuilder> hashBuilderFactory) { + this.hashBuilderFactory = hashBuilderFactory; + } + + /** * Get maximum batch size for delete and delete operations. * * @return Maximum batch size. @@ -1880,8 +1903,8 @@ public abstract class CacheAbstractJdbcStore<K, V> implements CacheStore<K, V>, colIdxs.put(meta.getColumnLabel(i), i); while (rs.next()) { - K1 key = buildObject(em.cacheName, em.keyType(), em.keyColumns(), colIdxs, rs); - V1 val = buildObject(em.cacheName, em.valueType(), em.valueColumns(), colIdxs, rs); + K1 key = buildObject(em.cacheName, em.keyType(), em.keyColumns(), colIdxs, true, rs); + V1 val = buildObject(em.cacheName, em.valueType(), em.valueColumns(), colIdxs, false, rs); clo.apply(key, val); } @@ -1975,8 +1998,8 @@ public abstract class CacheAbstractJdbcStore<K, V> implements CacheStore<K, V>, Map<K1, V1> entries = U.newHashMap(keys.size()); while (rs.next()) { - K1 key = buildObject(em.cacheName, em.keyType(), em.keyColumns(), em.loadColIdxs, rs); - V1 val = buildObject(em.cacheName, em.valueType(), em.valueColumns(), em.loadColIdxs, rs); + K1 key = buildObject(em.cacheName, em.keyType(), em.keyColumns(), em.loadColIdxs, true, rs); + V1 val = buildObject(em.cacheName, em.valueType(), em.valueColumns(), em.loadColIdxs, false, rs); entries.put(key, val); } http://git-wip-us.apache.org/repos/asf/ignite/blob/d5355def/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStore.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStore.java b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStore.java index 9a7996f..e29f6ca 100644 --- a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStore.java +++ b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStore.java @@ -119,23 +119,12 @@ public class CacheJdbcPojoStore<K, V> extends CacheAbstractJdbcStore<K, V> { obj.getClass() + ", property=" + fieldName + "]"); } - /** - * Construct object from query result. - * - * @param <R> Type of result object. - * @param cacheName Cache name. - * @param typeName Type name. - * @param fields Fields descriptors. - * @param loadColIdxs Select query columns index. - * @param rs ResultSet. - * @return Constructed object. - * @throws CacheLoaderException If failed to construct cache object. - */ + /** {@inheritDoc} */ @Override protected <R> R buildObject(@Nullable String cacheName, String typeName, - JdbcTypeField[] fields, Map<String, Integer> loadColIdxs, ResultSet rs) + JdbcTypeField[] fields, Map<String, Integer> loadColIdxs, boolean key, ResultSet rs) throws CacheLoaderException { return (R)(isKeepSerialized(cacheName, typeName) - ? buildPortableObject(cacheName, typeName, fields, loadColIdxs, rs) + ? buildPortableObject(cacheName, typeName, fields, loadColIdxs, key, rs) : buildPojoObject(cacheName, typeName, fields, loadColIdxs, rs)); } @@ -212,12 +201,13 @@ public class CacheJdbcPojoStore<K, V> extends CacheAbstractJdbcStore<K, V> { * @param typeName Type name. * @param fields Fields descriptors. * @param loadColIdxs Select query columns index. + * @param hash If {@code true} then build object with hash. * @param rs ResultSet. * @return Constructed portable object. * @throws CacheLoaderException If failed to construct portable object. */ protected Object buildPortableObject(String cacheName, String typeName, JdbcTypeField[] fields, - Map<String, Integer> loadColIdxs, ResultSet rs) throws CacheLoaderException { + Map<String, Integer> loadColIdxs, boolean hash, ResultSet rs) throws CacheLoaderException { Map<String, IgniteBiTuple<Boolean, Integer>> cacheTypeIds = portableTypeIds.get(cacheName); if (cacheTypeIds == null) @@ -245,19 +235,34 @@ public class CacheJdbcPojoStore<K, V> extends CacheAbstractJdbcStore<K, V> { else { PortableBuilder builder = ignite.portables().builder(tuple.get2()); - int hashCode = 0; // TODO: IGNITE-1753 hash code calculation could change !!! + if (hash) { + JdbcTypeHashBuilder hashBuilder = hashBuilderFactory.create(); - for (JdbcTypeField field : fields) { - Integer colIdx = loadColIdxs.get(field.getDatabaseFieldName()); + for (JdbcTypeField field : fields) { + Integer colIdx = loadColIdxs.get(field.getDatabaseFieldName()); + + String colName = field.getJavaFieldName(); - Object colVal = getColumnValue(rs, colIdx, field.getJavaFieldType()); + Object colVal = getColumnValue(rs, colIdx, field.getJavaFieldType()); - hashCode = 31 * hashCode + (colVal != null ? colVal.hashCode() : 0); + hashBuilder.toHash(colVal, typeName, colName); + + builder.setField(colName, colVal); + } - builder.setField(field.getJavaFieldName(), colVal); + return builder.hashCode(hashBuilder.hash()).build(); } + else { + for (JdbcTypeField field : fields) { + Integer colIdx = loadColIdxs.get(field.getDatabaseFieldName()); - return builder.hashCode(hashCode).build(); + Object colVal = getColumnValue(rs, colIdx, field.getJavaFieldType()); + + builder.setField(field.getJavaFieldName(), colVal); + } + + return builder.build(); + } } } catch (SQLException e) { http://git-wip-us.apache.org/repos/asf/ignite/blob/d5355def/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStoreConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStoreConfiguration.java b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStoreConfiguration.java index 206f1fe..1361e46 100644 --- a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStoreConfiguration.java +++ b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStoreConfiguration.java @@ -17,6 +17,7 @@ package org.apache.ignite.cache.store.jdbc; +import javax.cache.configuration.Factory; import org.apache.ignite.cache.store.jdbc.dialect.*; import java.io.*; @@ -55,6 +56,9 @@ public class CacheJdbcPojoStoreConfiguration implements Serializable { /** Parallel load cache minimum threshold. If {@code 0} then load sequentially. */ private int parallelLoadCacheMinThreshold = DFLT_PARALLEL_LOAD_CACHE_MINIMUM_THRESHOLD; + /** Factory for. */ + private Factory<JdbcTypeHashBuilder> hashBuilderFactory = JdbcTypeDefaultHashBuilderFactory.INSTANCE; + /** Types that store could process. */ private JdbcType[] types; @@ -79,6 +83,7 @@ public class CacheJdbcPojoStoreConfiguration implements Serializable { maxWrtAttempts = cfg.getMaximumWriteAttempts(); parallelLoadCacheMinThreshold = cfg.getParallelLoadCacheMinimumThreshold(); types = cfg.getTypes(); + hashBuilderFactory = cfg.getHashBuilderFactory(); } /** @@ -227,4 +232,25 @@ public class CacheJdbcPojoStoreConfiguration implements Serializable { return this; } + + /** + * Gets hash builder factory. + * + * @return Hash builder factory. + */ + public Factory<JdbcTypeHashBuilder> getHashBuilderFactory() { + return hashBuilderFactory; + } + + /** + * Sets hash builder factory.. + * + * @param hashBuilderFactory Hash builder factory. + * @return {@code This} for chaining. + */ + public CacheJdbcPojoStoreConfiguration setHashBuilderFactory(Factory<JdbcTypeHashBuilder> hashBuilderFactory) { + this.hashBuilderFactory = hashBuilderFactory; + + return this; + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/d5355def/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcType.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcType.java b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcType.java index 518ad8a..cee6263 100644 --- a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcType.java +++ b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcType.java @@ -54,6 +54,9 @@ public class JdbcType implements Serializable { /** If {@code true} object is stored as IgniteObject. */ private boolean keepSerialized; + /** Custom type hasher. */ + private JdbcTypeHashBuilder hasher; + /** * Empty constructor (all values are initialized to their defaults). */ http://git-wip-us.apache.org/repos/asf/ignite/blob/d5355def/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcTypeDefaultHashBuilder.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcTypeDefaultHashBuilder.java b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcTypeDefaultHashBuilder.java new file mode 100644 index 0000000..e7330e8 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcTypeDefaultHashBuilder.java @@ -0,0 +1,23 @@ +package org.apache.ignite.cache.store.jdbc; + +/** + * Default implementation of {@link JdbcTypeHashBuilder}. + * + * This implementation ignores type and field names. + */ +public class JdbcTypeDefaultHashBuilder implements JdbcTypeHashBuilder { + /** Hash code. */ + private int hash = 0; + + /** {@inheritDoc} */ + @Override public int toHash(Object val, String typeName, String fieldName) { + hash = 31 * hash + (val != null ? val.hashCode() : 0); + + return hash; + } + + /** {@inheritDoc} */ + @Override public int hash() { + return hash; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/d5355def/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcTypeDefaultHashBuilderFactory.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcTypeDefaultHashBuilderFactory.java b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcTypeDefaultHashBuilderFactory.java new file mode 100644 index 0000000..6dea4d1 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcTypeDefaultHashBuilderFactory.java @@ -0,0 +1,19 @@ +package org.apache.ignite.cache.store.jdbc; + +import javax.cache.configuration.Factory; + +/** + * Factory for creating default hash builder. + */ +public class JdbcTypeDefaultHashBuilderFactory implements Factory<JdbcTypeHashBuilder> { + /** */ + private static final long serialVersionUID = 0L; + + /** Instance of factory for reuse. */ + public final static JdbcTypeDefaultHashBuilderFactory INSTANCE = new JdbcTypeDefaultHashBuilderFactory(); + + /** {@inheritDoc} */ + @Override public JdbcTypeHashBuilder create() { + return new JdbcTypeDefaultHashBuilder(); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/d5355def/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcTypeHashBuilder.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcTypeHashBuilder.java b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcTypeHashBuilder.java new file mode 100644 index 0000000..971ae06 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/JdbcTypeHashBuilder.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.cache.store.jdbc; + +/** + * API for implementing custom hashing logic for portable objects on server side. + */ +public interface JdbcTypeHashBuilder { + /** + * Calculate hash code for specified value and field name. + * + * @param val Value to calculate hash code for. + * @param typeName Type name hash is calculating for. + * @param fieldName Field name that should participate in hash code calculation. + * @return Hash code. + */ + public int toHash(Object val, String typeName, String fieldName); + + /** + * @return Calculated hash code. + */ + public int hash(); +}