http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/GridHibernateTransactionalDataRegion.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/GridHibernateTransactionalDataRegion.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/GridHibernateTransactionalDataRegion.java deleted file mode 100644 index cca42de..0000000 --- a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/GridHibernateTransactionalDataRegion.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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.hibernate; - -import org.apache.ignite.*; -import org.apache.ignite.cache.*; -import org.hibernate.cache.*; -import org.hibernate.cache.spi.*; -import org.hibernate.cache.spi.access.*; - -import static org.apache.ignite.cache.CacheAtomicityMode.*; - -/** - * Implementation of {@link TransactionalDataRegion} (transactional means that - * data in the region is updated in connection with database transaction). - * This interface defines base contract for {@link EntityRegion}, {@link CollectionRegion} - * and {@link NaturalIdRegion}. - */ -public class GridHibernateTransactionalDataRegion extends GridHibernateRegion implements TransactionalDataRegion { - /** */ - private final CacheDataDescription dataDesc; - - /** - * @param factory Region factory. - * @param name Region name. - * @param ignite Grid. - * @param cache Region cache. - * @param dataDesc Region data description. - */ - public GridHibernateTransactionalDataRegion(GridHibernateRegionFactory factory, String name, - Ignite ignite, GridCache<Object, Object> cache, CacheDataDescription dataDesc) { - super(factory, name, ignite, cache); - - this.dataDesc = dataDesc; - } - - /** {@inheritDoc} */ - @Override public boolean isTransactionAware() { - return false; // This method is not used by Hibernate. - } - - /** {@inheritDoc} */ - @Override public CacheDataDescription getCacheDataDescription() { - return dataDesc; - } - - /** - * @param accessType Hibernate L2 cache access type. - * @return Access strategy for given access type. - */ - protected GridHibernateAccessStrategyAdapter createAccessStrategy(AccessType accessType) { - switch (accessType) { - case READ_ONLY: - return new GridHibernateReadOnlyAccessStrategy(ignite, cache); - - case NONSTRICT_READ_WRITE: - return new GridHibernateNonStrictAccessStrategy(ignite, cache, factory.threadLocalForCache(cache.name())); - - case READ_WRITE: - if (cache.configuration().getAtomicityMode() != TRANSACTIONAL) - throw new CacheException("Hibernate READ-WRITE access strategy must have Ignite cache with " + - "'TRANSACTIONAL' atomicity mode: " + cache.name()); - - return new GridHibernateReadWriteAccessStrategy(ignite, cache, factory.threadLocalForCache(cache.name())); - - case TRANSACTIONAL: - if (cache.configuration().getAtomicityMode() != TRANSACTIONAL) - throw new CacheException("Hibernate TRANSACTIONAL access strategy must have Ignite cache with " + - "'TRANSACTIONAL' atomicity mode: " + cache.name()); - - if (cache.configuration().getTransactionManagerLookupClassName() == null) - throw new CacheException("Hibernate TRANSACTIONAL access strategy must have Ignite cache with " + - "TransactionManagerLookup configured: " + cache.name()); - - return new GridHibernateTransactionalAccessStrategy(ignite, cache); - - default: - throw new IllegalArgumentException("Unknown Hibernate access type: " + accessType); - } - } -}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateAbstractRegionAccessStrategy.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateAbstractRegionAccessStrategy.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateAbstractRegionAccessStrategy.java new file mode 100644 index 0000000..993d087 --- /dev/null +++ b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateAbstractRegionAccessStrategy.java @@ -0,0 +1,97 @@ +/* + * 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.hibernate; + +import org.hibernate.cache.*; +import org.hibernate.cache.spi.access.*; +import org.jetbrains.annotations.*; + +/** + * Implementation of L2 cache access strategy delegating to {@link HibernateAccessStrategyAdapter}. + */ +public abstract class HibernateAbstractRegionAccessStrategy implements RegionAccessStrategy { + /** */ + protected final HibernateAccessStrategyAdapter stgy; + + /** + * @param stgy Access strategy implementation. + */ + protected HibernateAbstractRegionAccessStrategy(HibernateAccessStrategyAdapter stgy) { + this.stgy = stgy; + } + + /** {@inheritDoc} */ + @Nullable @Override public Object get(Object key, long txTs) throws CacheException { + return stgy.get(key); + } + + /** {@inheritDoc} */ + @Override public boolean putFromLoad(Object key, Object val, long txTs, Object ver) throws CacheException { + stgy.putFromLoad(key, val); + + return true; + } + + /** {@inheritDoc} */ + @Override public boolean putFromLoad(Object key, Object val, long txTs, Object ver, boolean minimalPutOverride) + throws CacheException { + stgy.putFromLoad(key, val, minimalPutOverride); + + return true; + } + + /** {@inheritDoc} */ + @Nullable @Override public SoftLock lockItem(Object key, Object ver) throws CacheException { + return stgy.lock(key); + } + + /** {@inheritDoc} */ + @Nullable @Override public SoftLock lockRegion() throws CacheException { + return stgy.lockRegion(); + } + + /** {@inheritDoc} */ + @Override public void unlockRegion(SoftLock lock) throws CacheException { + stgy.unlockRegion(lock); + } + + /** {@inheritDoc} */ + @Override public void unlockItem(Object key, SoftLock lock) throws CacheException { + stgy.unlock(key, lock); + } + + /** {@inheritDoc} */ + @Override public void remove(Object key) throws CacheException { + stgy.remove(key); + } + + /** {@inheritDoc} */ + @Override public void removeAll() throws CacheException { + stgy.removeAll(); + } + + /** {@inheritDoc} */ + @Override public void evict(Object key) throws CacheException { + stgy.evict(key); + } + + /** {@inheritDoc} */ + @Override public void evictAll() throws CacheException { + stgy.evictAll(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateAccessStrategyAdapter.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateAccessStrategyAdapter.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateAccessStrategyAdapter.java new file mode 100644 index 0000000..475e7d1 --- /dev/null +++ b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateAccessStrategyAdapter.java @@ -0,0 +1,369 @@ +/* + * 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.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.apache.ignite.internal.*; +import org.apache.ignite.internal.processors.cache.*; +import org.apache.ignite.internal.util.typedef.internal.*; +import org.apache.ignite.lang.*; +import org.apache.ignite.resources.*; +import org.hibernate.cache.*; +import org.hibernate.cache.spi.access.*; +import org.jetbrains.annotations.*; + +import java.io.*; + +/** + * Common interface used to implement Hibernate L2 cache access strategies ({@link RegionAccessStrategy}, + * {@link EntityRegionAccessStrategy} and {@link CollectionRegionAccessStrategy}). + * <p> + * The expected sequences of steps related to various CRUD operations executed by Hibernate are: + * <p> + * Insert: + * <ul> + * <li>Start DB transaction.</li> + * <li>Execute database insert.</li> + * <li>Call {@link HibernateAccessStrategyAdapter#insert}.</li> + * <li>Commit DB transaction.</li> + * <li>Call {@link HibernateAccessStrategyAdapter#afterInsert}.</li> + * </ul> + * In case if some step fails and DB transaction is rolled back then + * {@link HibernateAccessStrategyAdapter#afterInsert} is not called. + * <p> + * Update: + * <ul> + * <li>Start DB transaction.</li> + * <li>Call {@link HibernateAccessStrategyAdapter#lock}.</li> + * <li>Execute database update.</li> + * <li>Call {@link HibernateAccessStrategyAdapter#update}.</li> + * <li>Commit DB transaction.</li> + * <li>Call {@link HibernateAccessStrategyAdapter#afterUpdate}.</li> + * </ul> + * In case if {@link HibernateAccessStrategyAdapter#lock} was called, but some other step fails and DB + * transaction is rolled back then {@link HibernateAccessStrategyAdapter#unlock} is called for all locked keys. + * <p> + * Delete: + * <ul> + * <li>Start DB transaction.</li> + * <li>Call {@link HibernateAccessStrategyAdapter#lock} for removing key.</li> + * <li>Execute database delete.</li> + * <li>Call {@link HibernateAccessStrategyAdapter#remove}.</li> + * <li>Commit DB transaction.</li> + * <li>Call {@link HibernateAccessStrategyAdapter#unlock}.</li> + * </ul> + * In case if {@link HibernateAccessStrategyAdapter#lock} was called, but some other step fails and DB + * transaction is rolled back then {@link HibernateAccessStrategyAdapter#unlock} is called for all locked keys. + * <p> + * In case if custom SQL update query is executed Hibernate clears entire cache region, + * for this case operations sequence is: + * <ul> + * <li>Start DB transaction.</li> + * <li>Call {@link HibernateAccessStrategyAdapter#lockRegion}.</li> + * <li>Execute database query.</li> + * <li>Call {@link HibernateAccessStrategyAdapter#removeAll}.</li> + * <li>Commit DB transaction.</li> + * <li>Call {@link HibernateAccessStrategyAdapter#unlockRegion}.</li> + * </ul> + */ +public abstract class HibernateAccessStrategyAdapter { + /** */ + protected final GridCache<Object, Object> cache; + + /** Grid. */ + protected final Ignite ignite; + + /** */ + protected final IgniteLogger log; + + /** + * @param ignite Grid. + * @param cache Cache. + */ + protected HibernateAccessStrategyAdapter(Ignite ignite, GridCache<Object, Object> cache) { + this.cache = cache; + this.ignite = ignite; + + log = ignite.log(); + } + + /** + * Gets value from cache. Used by {@link RegionAccessStrategy#get}. + * + * @param key Key. + * @return Cached value. + * @throws CacheException If failed. + */ + @Nullable protected Object get(Object key) throws CacheException { + try { + return cache.get(key); + } + catch (IgniteCheckedException e) { + throw new CacheException(e); + } + } + + /** + * Puts in cache value loaded from the database. Used by {@link RegionAccessStrategy#putFromLoad}. + * + * @param key Key. + * @param val Value. + * @param minimalPutOverride MinimalPut flag + * @throws CacheException If failed. + */ + protected void putFromLoad(Object key, Object val, boolean minimalPutOverride) throws CacheException { + putFromLoad(key, val); + } + + /** + * Puts in cache value loaded from the database. Used by {@link RegionAccessStrategy#putFromLoad}. + * + * @param key Key. + * @param val Value. + * @throws CacheException If failed. + */ + protected void putFromLoad(Object key, Object val) throws CacheException { + try { + cache.putx(key, val); + } + catch (IgniteCheckedException e) { + throw new CacheException(e); + } + } + + /** + * Called during database transaction execution before Hibernate attempts to update or remove given key. + * Used by {@link RegionAccessStrategy#lockItem}. + * + * @param key Key. + * @return Lock representation or {@code null}. + * @throws CacheException If failed. + */ + @Nullable protected abstract SoftLock lock(Object key) throws CacheException; + + /** + * Called after Hibernate failed to update or successfully removed given key. + * Used by {@link RegionAccessStrategy#unlockItem}. + * + * @param key Key. + * @param lock The lock previously obtained from {@link #lock} + * @throws CacheException If failed. + */ + protected abstract void unlock(Object key, SoftLock lock) throws CacheException; + + /** + * Called after Hibernate updated object in the database but before transaction completed. + * Used by {@link EntityRegionAccessStrategy#update} and {@link NaturalIdRegionAccessStrategy#update}. + * + * @param key Key. + * @param val Value. + * @return {@code True} if operation updated cache. + * @throws CacheException If failed. + */ + protected abstract boolean update(Object key, Object val) throws CacheException; + + /** + * Called after Hibernate updated object in the database and transaction successfully completed. + * Used by {@link EntityRegionAccessStrategy#afterUpdate} and {@link NaturalIdRegionAccessStrategy#afterUpdate}. + * + * @param key Key. + * @param val Value. + * @param lock The lock previously obtained from {@link #lock} + * @return {@code True} if operation updated cache. + * @throws CacheException If failed. + */ + protected abstract boolean afterUpdate(Object key, Object val, SoftLock lock) throws CacheException; + + /** + * Called after Hibernate inserted object in the database but before transaction completed. + * Used by {@link EntityRegionAccessStrategy#insert} and {@link NaturalIdRegionAccessStrategy#insert}. + * + * @param key Key. + * @param val Value. + * @return {@code True} if operation updated cache. + * @throws CacheException If failed. + */ + protected abstract boolean insert(Object key, Object val) throws CacheException; + + /** + * Called after Hibernate inserted object in the database and transaction successfully completed. + * Used by {@link EntityRegionAccessStrategy#afterInsert} and {@link NaturalIdRegionAccessStrategy#afterInsert}. + * + * @param key Key. + * @param val Value. + * @return {@code True} if operation updated cache. + * @throws CacheException If failed. + */ + protected abstract boolean afterInsert(Object key, Object val) throws CacheException; + + /** + * Called after Hibernate removed object from database but before transaction completed. + * Used by {@link RegionAccessStrategy#remove}. + * + * @param key Key, + * @throws CacheException If failed. + */ + protected abstract void remove(Object key) throws CacheException; + + /** + * Called to remove object from cache without regard to transaction. + * Used by {@link RegionAccessStrategy#evict}. + * + * @param key Key. + * @throws CacheException If failed. + */ + protected void evict(Object key) throws CacheException { + evict(ignite, cache, key); + } + + /** + * Called to remove all data from cache without regard to transaction. + * Used by {@link RegionAccessStrategy#evictAll}. + * + * @throws CacheException If failed. + */ + protected void evictAll() throws CacheException { + evictAll(cache); + } + + /** + * Called during database transaction execution before Hibernate executed + * update operation which should invalidate entire cache region. + * Used by {@link RegionAccessStrategy#lockRegion}. + * + * @throws CacheException If failed. + * @return Lock representation or {@code null}. + */ + @Nullable protected SoftLock lockRegion() throws CacheException { + return null; + } + + /** + * Called after transaction clearing entire cache region completed. + * Used by {@link RegionAccessStrategy#unlockRegion}. + * + * @param lock The lock previously obtained from {@link #lockRegion} + * @throws CacheException If failed. + */ + protected void unlockRegion(SoftLock lock) throws CacheException { + // No-op. + } + + /** + * Called during database transaction execution to clear entire cache region after + * Hibernate executed database update, but before transaction completed. + * Used by {@link RegionAccessStrategy#removeAll}. + * + * @throws CacheException If failed. + */ + protected final void removeAll() throws CacheException { + evictAll(); + } + + /** + * Called to remove object from cache without regard to transaction. + * + * @param ignite Grid. + * @param cache Cache. + * @param key Key. + * @throws CacheException If failed. + */ + static void evict(Ignite ignite, CacheProjection<Object,Object> cache, Object key) throws CacheException { + try { + ignite.compute(cache.gridProjection()).call(new ClearKeyCallable(key, cache.name())); + } + catch (IgniteException e) { + throw new CacheException(e); + } + } + + /** + * Called to remove all data from cache without regard to transaction. + * + * @param cache Cache. + * @throws CacheException If failed. + */ + static void evictAll(CacheProjection<Object,Object> cache) throws CacheException { + try { + cache.clear(); + } + catch (IgniteCheckedException e) { + throw new CacheException(e); + } + } + + /** + * Callable invalidates given key. + */ + private static class ClearKeyCallable implements IgniteCallable<Void>, Externalizable { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + @IgniteInstanceResource + private Ignite ignite; + + /** */ + private Object key; + + /** */ + private String cacheName; + + /** + * Empty constructor required by {@link Externalizable}. + */ + public ClearKeyCallable() { + // No-op. + } + + /** + * @param key Key to clear. + * @param cacheName Cache name. + */ + private ClearKeyCallable(Object key, String cacheName) { + this.key = key; + this.cacheName = cacheName; + } + + /** {@inheritDoc} */ + @Override public Void call() throws IgniteCheckedException { + GridCache<Object, Object> cache = ((IgniteKernal)ignite).cache(cacheName); + + assert cache != null; + + cache.clearLocally(key); + + return null; + } + + /** {@inheritDoc} */ + @Override public void writeExternal(ObjectOutput out) throws IOException { + out.writeObject(key); + + U.writeString(out, cacheName); + } + + /** {@inheritDoc} */ + @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + key = in.readObject(); + + cacheName = U.readString(in); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateCollectionRegion.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateCollectionRegion.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateCollectionRegion.java new file mode 100644 index 0000000..0f19441 --- /dev/null +++ b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateCollectionRegion.java @@ -0,0 +1,99 @@ +/* + * 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.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.hibernate.cache.*; +import org.hibernate.cache.spi.*; +import org.hibernate.cache.spi.access.*; + +/** + * Implementation of {@link CollectionRegion}. This region is used to store collection data. + * <p> + * L2 cache for collection can be enabled in the Hibernate configuration file: + * <pre name="code" class="xml"> + * <hibernate-configuration> + * <!-- Enable L2 cache. --> + * <property name="cache.use_second_level_cache">true</property> + * + * <!-- Use Ignite as L2 cache provider. --> + * <property name="cache.region.factory_class">org.apache.ignite.cache.hibernate.HibernateRegionFactory</property> + * + * <!-- Specify entities. --> + * <mapping class="com.example.Entity"/> + * <mapping class="com.example.ChildEntity"/> + * + * <!-- Enable L2 cache with nonstrict-read-write access strategy for entities and collection. --> + * <collection-cache collection="com.example.Entity" usage="nonstrict-read-write"/> + * <collection-cache collection="com.example.ChildEntity" usage="nonstrict-read-write"/> + * <collection-cache collection="com.example.Entity.children" usage="nonstrict-read-write"/> + * </hibernate-configuration> + * </pre> + * Also cache for collection can be enabled using annotations: + * <pre name="code" class="java"> + * @javax.persistence.Entity + * public class Entity { + * ... + * + * @javax.persistence.OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER) + * @javax.persistence.JoinColumn(name="PARENT_ID") + * @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + * public List<ChildEntity> getChildren() {...} + * } + * </pre> + * Note: the collection cache does not cache the state of the actual entities in the cache, it caches only identifier + * values. For this reason, the collection cache should always be used in conjunction with + * the second-level cache for those entities expected to be cached as part of a collection cache. + */ +public class HibernateCollectionRegion extends HibernateTransactionalDataRegion implements CollectionRegion { + /** + * @param factory Region factory. + * @param name Region name. + * @param ignite Grid. + * @param cache Region cache. + * @param dataDesc Region data description. + */ + public HibernateCollectionRegion(HibernateRegionFactory factory, String name, + Ignite ignite, GridCache<Object, Object> cache, CacheDataDescription dataDesc) { + super(factory, name, ignite, cache, dataDesc); + } + + /** {@inheritDoc} */ + @Override public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException { + return new AccessStrategy(createAccessStrategy(accessType)); + } + + /** + * Collection region access strategy. + */ + private class AccessStrategy extends HibernateAbstractRegionAccessStrategy + implements CollectionRegionAccessStrategy { + /** + * @param stgy Access strategy implementation. + */ + private AccessStrategy(HibernateAccessStrategyAdapter stgy) { + super(stgy); + } + + /** {@inheritDoc} */ + @Override public CollectionRegion getRegion() { + return HibernateCollectionRegion.this; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateEntityRegion.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateEntityRegion.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateEntityRegion.java new file mode 100644 index 0000000..52d4365 --- /dev/null +++ b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateEntityRegion.java @@ -0,0 +1,110 @@ +/* + * 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.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.hibernate.cache.*; +import org.hibernate.cache.spi.*; +import org.hibernate.cache.spi.access.*; + +/** + * Implementation of {@link EntityRegion}. This region is used to store entity data. + * <p> + * L2 cache for entity can be enabled in the Hibernate configuration file: + * <pre name="code" class="xml"> + * <hibernate-configuration> + * <!-- Enable L2 cache. --> + * <property name="cache.use_second_level_cache">true</property> + * + * <!-- Use Ignite as L2 cache provider. --> + * <property name="cache.region.factory_class">org.apache.ignite.cache.hibernate.HibernateRegionFactory</property> + * + * <!-- Specify entity. --> + * <mapping class="com.example.Entity"/> + * + * <!-- Enable L2 cache with nonstrict-read-write access strategy for entity. --> + * <class-cache class="com.example.Entity" usage="nonstrict-read-write"/> + * </hibernate-configuration> + * </pre> + * Also cache for entity can be enabled using annotations: + * <pre name="code" class="java"> + * @javax.persistence.Entity + * @javax.persistence.Cacheable + * @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + * public class Entity { ... } + * </pre> + */ +public class HibernateEntityRegion extends HibernateTransactionalDataRegion implements EntityRegion { + /** + * @param factory Region factory. + * @param name Region name. + * @param ignite Grid. + * @param cache Region cache, + * @param dataDesc Region data description. + */ + public HibernateEntityRegion(HibernateRegionFactory factory, String name, Ignite ignite, + GridCache<Object, Object> cache, CacheDataDescription dataDesc) { + super(factory, name, ignite, cache, dataDesc); + } + + /** {@inheritDoc} */ + @Override public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException { + return new AccessStrategy(createAccessStrategy(accessType)); + } + + /** + * Entity region access strategy. + */ + private class AccessStrategy extends HibernateAbstractRegionAccessStrategy + implements EntityRegionAccessStrategy { + /** + * @param stgy Access strategy implementation. + */ + private AccessStrategy(HibernateAccessStrategyAdapter stgy) { + super(stgy); + } + + /** {@inheritDoc} */ + @Override public EntityRegion getRegion() { + return HibernateEntityRegion.this; + } + + /** {@inheritDoc} */ + @Override public boolean insert(Object key, Object val, Object ver) throws CacheException { + return stgy.insert(key, val); + } + + /** {@inheritDoc} */ + @Override public boolean afterInsert(Object key, Object val, Object ver) throws CacheException { + return stgy.afterInsert(key, val); + } + + /** {@inheritDoc} */ + @Override public boolean update(Object key, Object val, Object currVer, Object previousVer) + throws CacheException { + return stgy.update(key, val); + } + + /** {@inheritDoc} */ + @Override public boolean afterUpdate(Object key, Object val, Object currVer, Object previousVer, SoftLock lock) + throws CacheException { + return stgy.afterUpdate(key, val, lock); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateGeneralDataRegion.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateGeneralDataRegion.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateGeneralDataRegion.java new file mode 100644 index 0000000..1c46c9e --- /dev/null +++ b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateGeneralDataRegion.java @@ -0,0 +1,69 @@ +/* + * 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.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.hibernate.cache.*; +import org.hibernate.cache.spi.*; +import org.jetbrains.annotations.*; + +/** + * Implementation of {@link GeneralDataRegion}. This interface defines common contract for {@link QueryResultsRegion} + * and {@link TimestampsRegion}. + */ +public class HibernateGeneralDataRegion extends HibernateRegion implements GeneralDataRegion { + /** + * @param factory Region factory. + * @param name Region name. + * @param ignite Grid. + * @param cache Region cache. + */ + public HibernateGeneralDataRegion(HibernateRegionFactory factory, String name, + Ignite ignite, GridCache<Object, Object> cache) { + super(factory, name, ignite, cache); + } + + /** {@inheritDoc} */ + @Nullable @Override public Object get(Object key) throws CacheException { + try { + return cache.get(key); + } catch (IgniteCheckedException e) { + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Override public void put(Object key, Object val) throws CacheException { + try { + cache.putx(key, val); + } catch (IgniteCheckedException e) { + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Override public void evict(Object key) throws CacheException { + HibernateAccessStrategyAdapter.evict(ignite, cache, key); + } + + /** {@inheritDoc} */ + @Override public void evictAll() throws CacheException { + HibernateAccessStrategyAdapter.evictAll(cache); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateNaturalIdRegion.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateNaturalIdRegion.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateNaturalIdRegion.java new file mode 100644 index 0000000..bae2aa9 --- /dev/null +++ b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateNaturalIdRegion.java @@ -0,0 +1,98 @@ +/* + * 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.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.hibernate.cache.*; +import org.hibernate.cache.spi.*; +import org.hibernate.cache.spi.access.*; + +/** + * Implementation of {@link NaturalIdRegion}. This region is used to store naturalId data. + * <p> + * L2 cache for entity naturalId and target cache region can be set using annotations: + * <pre name="code" class="java"> + * @javax.persistence.Entity + * @javax.persistence.Cacheable + * @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + * @org.hibernate.annotations.NaturalIdCache + * public class Entity { + * @org.hibernate.annotations.NaturalId + * private String entityCode; + * + * ... + * } + * </pre> + */ +public class HibernateNaturalIdRegion extends HibernateTransactionalDataRegion implements NaturalIdRegion { + /** + * @param factory Region factory. + * @param name Region name. + * @param ignite Grid. + * @param cache Region cache, + * @param dataDesc Region data description. + */ + public HibernateNaturalIdRegion(HibernateRegionFactory factory, String name, + Ignite ignite, GridCache<Object, Object> cache, CacheDataDescription dataDesc) { + super(factory, name, ignite, cache, dataDesc); + } + + /** {@inheritDoc} */ + @Override public NaturalIdRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException { + return new AccessStrategy(createAccessStrategy(accessType)); + } + + /** + * NaturalId region access strategy. + */ + private class AccessStrategy extends HibernateAbstractRegionAccessStrategy implements + NaturalIdRegionAccessStrategy { + /** + * @param stgy Access strategy implementation. + */ + private AccessStrategy(HibernateAccessStrategyAdapter stgy) { + super(stgy); + } + + /** {@inheritDoc} */ + @Override public NaturalIdRegion getRegion() { + return HibernateNaturalIdRegion.this; + } + + /** {@inheritDoc} */ + @Override public boolean insert(Object key, Object val) throws CacheException { + return stgy.insert(key, val); + } + + /** {@inheritDoc} */ + @Override public boolean afterInsert(Object key, Object val) throws CacheException { + return stgy.afterInsert(key, val); + } + + /** {@inheritDoc} */ + @Override public boolean update(Object key, Object val) throws CacheException { + return stgy.update(key, val); + } + + /** {@inheritDoc} */ + @Override public boolean afterUpdate(Object key, Object val, SoftLock lock) throws CacheException { + return stgy.afterUpdate(key, val, lock); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateNonStrictAccessStrategy.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateNonStrictAccessStrategy.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateNonStrictAccessStrategy.java new file mode 100644 index 0000000..0f6d565 --- /dev/null +++ b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateNonStrictAccessStrategy.java @@ -0,0 +1,220 @@ +/* + * 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.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.apache.ignite.internal.util.*; +import org.apache.ignite.internal.util.typedef.*; +import org.hibernate.cache.*; +import org.hibernate.cache.spi.access.*; +import org.jetbrains.annotations.*; + +import java.util.*; + +/** + * Implementation of {@link AccessType#NONSTRICT_READ_WRITE} cache access strategy. + * <p> + * Configuration of L2 cache and per-entity cache access strategy can be set in the + * Hibernate configuration file: + * <pre name="code" class="xml"> + * <hibernate-configuration> + * <!-- Enable L2 cache. --> + * <property name="cache.use_second_level_cache">true</property> + * + * <!-- Use Ignite as L2 cache provider. --> + * <property name="cache.region.factory_class">org.apache.ignite.cache.hibernate.HibernateRegionFactory</property> + * + * <!-- Specify entity. --> + * <mapping class="com.example.Entity"/> + * + * <!-- Enable L2 cache with nonstrict-read-write access strategy for entity. --> + * <class-cache class="com.example.Entity" usage="nonstrict-read-write"/> + * </hibernate-configuration> + * </pre> + * Also cache access strategy can be set using annotations: + * <pre name="code" class="java"> + * @javax.persistence.Entity + * @javax.persistence.Cacheable + * @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + * public class Entity { ... } + * </pre> + */ +public class HibernateNonStrictAccessStrategy extends HibernateAccessStrategyAdapter { + /** */ + private final ThreadLocal<WriteContext> writeCtx; + + /** + * @param ignite Grid. + * @param cache Cache. + * @param writeCtx Thread local instance used to track updates done during one Hibernate transaction. + */ + protected HibernateNonStrictAccessStrategy(Ignite ignite, GridCache<Object, Object> cache, ThreadLocal writeCtx) { + super(ignite, cache); + + this.writeCtx = (ThreadLocal<WriteContext>)writeCtx; + } + + /** {@inheritDoc} */ + @Nullable @Override protected SoftLock lock(Object key) throws CacheException { + WriteContext ctx = writeCtx.get(); + + if (ctx == null) + writeCtx.set(ctx = new WriteContext()); + + ctx.locked(key); + + return null; + } + + /** {@inheritDoc} */ + @Override protected void unlock(Object key, SoftLock lock) throws CacheException { + try { + WriteContext ctx = writeCtx.get(); + + if (ctx != null && ctx.unlocked(key)) { + writeCtx.remove(); + + ctx.updateCache(cache); + } + } + catch (IgniteCheckedException e) { + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Override protected boolean update(Object key, Object val) throws CacheException { + return false; + } + + /** {@inheritDoc} */ + @Override protected boolean afterUpdate(Object key, Object val, SoftLock lock) throws CacheException { + WriteContext ctx = writeCtx.get(); + + if (ctx != null) { + ctx.updated(key, val); + + unlock(key, lock); + + return true; + } + + return false; + } + + /** {@inheritDoc} */ + @Override protected boolean insert(Object key, Object val) throws CacheException { + return false; + } + + /** {@inheritDoc} */ + @Override protected boolean afterInsert(Object key, Object val) throws CacheException { + try { + cache.putx(key, val); + + return true; + } + catch (IgniteCheckedException e) { + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Override protected void remove(Object key) throws CacheException { + WriteContext ctx = writeCtx.get(); + + if (ctx != null) + ctx.removed(key); + } + + /** + * Information about updates done during single database transaction. + */ + @SuppressWarnings("TypeMayBeWeakened") + private static class WriteContext { + /** */ + private Map<Object, Object> updates; + + /** */ + private Set<Object> rmvs; + + /** */ + private Set<Object> locked = new GridLeanSet<>(); + + /** + * Marks key as locked. + * + * @param key Key. + */ + void locked(Object key) { + locked.add(key); + } + + /** + * Marks key as unlocked. + * + * @param key Key. + * @return {@code True} if last locked key was unlocked. + */ + boolean unlocked(Object key) { + locked.remove(key); + + return locked.isEmpty(); + } + + /** + * Marks key as updated. + * + * @param key Key. + * @param val Value. + */ + void updated(Object key, Object val) { + if (updates == null) + updates = new GridLeanMap<>(); + + updates.put(key, val); + } + + /** + * Marks key as removed. + * + * @param key Key. + */ + void removed(Object key) { + if (rmvs == null) + rmvs = new GridLeanSet<>(); + + rmvs.add(key); + } + + /** + * Updates cache. + * + * @param cache Cache. + * @throws IgniteCheckedException If failed. + */ + void updateCache(GridCache<Object, Object> cache) throws IgniteCheckedException { + if (!F.isEmpty(rmvs)) + cache.removeAll(rmvs); + + if (!F.isEmpty(updates)) + cache.putAll(updates); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateQueryResultsRegion.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateQueryResultsRegion.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateQueryResultsRegion.java new file mode 100644 index 0000000..436abdf --- /dev/null +++ b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateQueryResultsRegion.java @@ -0,0 +1,71 @@ +/* + * 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.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.hibernate.*; +import org.hibernate.cache.spi.*; + +/** + * Implementation of {@link QueryResultsRegion}. This region is used to store query results. + * <p> + * Query results caching can be enabled in the Hibernate configuration file: + * <pre name="code" class="xml"> + * <hibernate-configuration> + * <!-- Enable L2 cache. --> + * <property name="cache.use_second_level_cache">true</property> + * + * <!-- Enable query cache. --> + * <property name="cache.use_second_level_cache">true</property> + + * <!-- Use Ignite as L2 cache provider. --> + * <property name="cache.region.factory_class">org.apache.ignite.cache.hibernate.HibernateRegionFactory</property> + * + * <!-- Specify entity. --> + * <mapping class="com.example.Entity"/> + * + * <!-- Enable L2 cache with nonstrict-read-write access strategy for entity. --> + * <class-cache class="com.example.Entity" usage="nonstrict-read-write"/> + * </hibernate-configuration> + * </pre> + * By default queries are not cached even after enabling query caching, to enable results caching for a particular + * query, call {@link Query#setCacheable(boolean)}: + * <pre name="code" class="java"> + * Session ses = getSession(); + * + * Query qry = ses.createQuery("..."); + * + * qry.setCacheable(true); // Enable L2 cache for query. + * </pre> + * Note: the query cache does not cache the state of the actual entities in the cache, it caches only identifier + * values. For this reason, the query cache should always be used in conjunction with + * the second-level cache for those entities expected to be cached as part of a query result cache + */ +public class HibernateQueryResultsRegion extends HibernateGeneralDataRegion implements QueryResultsRegion { + /** + * @param factory Region factory. + * @param name Region name. + * @param ignite Grid. + * @param cache Region cache. + */ + public HibernateQueryResultsRegion(HibernateRegionFactory factory, String name, + Ignite ignite, GridCache<Object, Object> cache) { + super(factory, name, ignite, cache); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateReadOnlyAccessStrategy.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateReadOnlyAccessStrategy.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateReadOnlyAccessStrategy.java new file mode 100644 index 0000000..fdacd39 --- /dev/null +++ b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateReadOnlyAccessStrategy.java @@ -0,0 +1,106 @@ +/* + * 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.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.hibernate.cache.*; +import org.hibernate.cache.spi.access.*; +import org.jetbrains.annotations.*; + +/** + * Implementation of {@link AccessType#READ_ONLY} cache access strategy. + * <p> + * Configuration of L2 cache and per-entity cache access strategy can be set in the + * Hibernate configuration file: + * <pre name="code" class="xml"> + * <hibernate-configuration> + * <!-- Enable L2 cache. --> + * <property name="cache.use_second_level_cache">true</property> + * + * <!-- Use Ignite as L2 cache provider. --> + * <property name="cache.region.factory_class">org.apache.ignite.cache.hibernate.HibernateRegionFactory</property> + * + * <!-- Specify entity. --> + * <mapping class="com.example.Entity"/> + * + * <!-- Enable L2 cache with read-only access strategy for entity. --> + * <class-cache class="com.example.Entity" usage="read-only"/> + * </hibernate-configuration> + * </pre> + * Also cache access strategy can be set using annotations: + * <pre name="code" class="java"> + * @javax.persistence.Entity + * @javax.persistence.Cacheable + * @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY) + * public class Entity { ... } + * </pre> + + * + */ +public class HibernateReadOnlyAccessStrategy extends HibernateAccessStrategyAdapter { + /** + * @param ignite Grid. + * @param cache Cache. + */ + public HibernateReadOnlyAccessStrategy(Ignite ignite, GridCache<Object, Object> cache) { + super(ignite, cache); + } + + /** {@inheritDoc} */ + @Override protected boolean insert(Object key, Object val) throws CacheException { + return false; + } + + /** {@inheritDoc} */ + @Override protected boolean afterInsert(Object key, Object val) throws CacheException { + try { + cache.putx(key, val); + + return true; + } + catch (IgniteCheckedException e) { + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Nullable @Override protected SoftLock lock(Object key) throws CacheException { + return null; + } + + /** {@inheritDoc} */ + @Override protected void unlock(Object key, SoftLock lock) throws CacheException { + // No-op. + } + + /** {@inheritDoc} */ + @Override protected void remove(Object key) throws CacheException { + // No-op. + } + + /** {@inheritDoc} */ + @Override protected boolean update(Object key, Object val) throws CacheException { + throw new UnsupportedOperationException("Updates are not supported for read-only access strategy."); + } + + /** {@inheritDoc} */ + @Override protected boolean afterUpdate(Object key, Object val, SoftLock lock) throws CacheException { + throw new UnsupportedOperationException("Updates are not supported for read-only access strategy."); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateReadWriteAccessStrategy.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateReadWriteAccessStrategy.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateReadWriteAccessStrategy.java new file mode 100644 index 0000000..3ca466d --- /dev/null +++ b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateReadWriteAccessStrategy.java @@ -0,0 +1,282 @@ +/* + * 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.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.apache.ignite.internal.util.*; +import org.apache.ignite.transactions.*; +import org.hibernate.cache.*; +import org.hibernate.cache.spi.access.*; + +import java.util.*; + +import static org.apache.ignite.transactions.TransactionConcurrency.*; +import static org.apache.ignite.transactions.TransactionIsolation.*; + +/** + * Implementation of {@link AccessType#READ_WRITE} cache access strategy. + * <p> + * Configuration of L2 cache and per-entity cache access strategy can be set in the + * Hibernate configuration file: + * <pre name="code" class="xml"> + * <hibernate-configuration> + * <!-- Enable L2 cache. --> + * <property name="cache.use_second_level_cache">true</property> + * + * <!-- Use Ignite as L2 cache provider. --> + * <property name="cache.region.factory_class">org.apache.ignite.cache.hibernate.HibernateRegionFactory</property> + * + * <!-- Specify entity. --> + * <mapping class="com.example.Entity"/> + * + * <!-- Enable L2 cache with read-write access strategy for entity. --> + * <class-cache class="com.example.Entity" usage="read-write"/> + * </hibernate-configuration> + * </pre> + * Also cache access strategy can be set using annotations: + * <pre name="code" class="java"> + * @javax.persistence.Entity + * @javax.persistence.Cacheable + * @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + * public class Entity { ... } + * </pre> + */ +public class HibernateReadWriteAccessStrategy extends HibernateAccessStrategyAdapter { + /** */ + private final ThreadLocal<TxContext> txCtx; + + /** + * @param ignite Grid. + * @param cache Cache. + * @param txCtx Thread local instance used to track updates done during one Hibernate transaction. + */ + protected HibernateReadWriteAccessStrategy(Ignite ignite, GridCache<Object, Object> cache, ThreadLocal txCtx) { + super(ignite, cache); + + this.txCtx = (ThreadLocal<TxContext>)txCtx; + } + + /** {@inheritDoc} */ + @Override protected Object get(Object key) throws CacheException { + try { + return cache.get(key); + } + catch (IgniteCheckedException e) { + rollbackCurrentTx(); + + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Override protected void putFromLoad(Object key, Object val) throws CacheException { + try { + cache.putx(key, val); + } + catch (IgniteCheckedException e) { + rollbackCurrentTx(); + + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Override protected SoftLock lock(Object key) throws CacheException { + try { + TxContext ctx = txCtx.get(); + + if (ctx == null) + txCtx.set(ctx = new TxContext()); + + lockKey(key); + + ctx.locked(key); + + return null; + } + catch (IgniteCheckedException e) { + rollbackCurrentTx(); + + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Override protected void unlock(Object key, SoftLock lock) throws CacheException { + try { + TxContext ctx = txCtx.get(); + + if (ctx != null) + unlock(ctx, key); + } + catch (IgniteCheckedException e) { + rollbackCurrentTx(); + + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Override protected boolean update(Object key, Object val) throws CacheException { + return false; + } + + /** {@inheritDoc} */ + @Override protected boolean afterUpdate(Object key, Object val, SoftLock lock) throws CacheException { + try { + TxContext ctx = txCtx.get(); + + if (ctx != null) { + cache.putx(key, val); + + unlock(ctx, key); + + return true; + } + + return false; + } + catch (IgniteCheckedException e) { + rollbackCurrentTx(); + + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Override protected boolean insert(Object key, Object val) throws CacheException { + return false; + } + + /** {@inheritDoc} */ + @Override protected boolean afterInsert(Object key, Object val) throws CacheException { + try { + cache.putx(key, val); + + return true; + } + catch (IgniteCheckedException e) { + rollbackCurrentTx(); + + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Override protected void remove(Object key) throws CacheException { + try { + TxContext ctx = txCtx.get(); + + if (ctx != null) + cache.removex(key); + } + catch (IgniteCheckedException e) { + rollbackCurrentTx(); + + throw new CacheException(e); + } + } + + /** + * + * @param ctx Transaction context. + * @param key Key. + * @throws IgniteCheckedException If failed. + */ + private void unlock(TxContext ctx, Object key) throws IgniteCheckedException { + if (ctx.unlocked(key)) { // Finish transaction if last key is unlocked. + txCtx.remove(); + + Transaction tx = cache.tx(); + + assert tx != null; + + try { + tx.commit(); + } + finally { + tx.close(); + } + + assert cache.tx() == null; + } + } + + /** + * Roll backs current transaction. + */ + private void rollbackCurrentTx() { + try { + TxContext ctx = txCtx.get(); + + if (ctx != null) { + txCtx.remove(); + + Transaction tx = cache.tx(); + + if (tx != null) + tx.rollback(); + } + } + catch (IgniteException e) { + log.error("Failed to rollback cache transaction.", e); + } + } + + /** + * @param key Key. + * @throws IgniteCheckedException If failed. + */ + private void lockKey(Object key) throws IgniteCheckedException { + if (cache.tx() == null) + cache.txStart(PESSIMISTIC, REPEATABLE_READ); + + cache.get(key); // Acquire distributed lock. + } + + /** + * Information about updates done during single database transaction. + */ + @SuppressWarnings("TypeMayBeWeakened") + private static class TxContext { + /** */ + private Set<Object> locked = new GridLeanSet<>(); + + /** + * Marks key as locked. + * + * @param key Key. + */ + void locked(Object key) { + locked.add(key); + } + + /** + * Marks key as unlocked. + * + * @param key Key. + * @return {@code True} if last locked key was unlocked. + */ + boolean unlocked(Object key) { + locked.remove(key); + + return locked.isEmpty(); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateRegion.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateRegion.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateRegion.java new file mode 100644 index 0000000..30eb098 --- /dev/null +++ b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateRegion.java @@ -0,0 +1,101 @@ +/* + * 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.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.hibernate.cache.*; +import org.hibernate.cache.spi.*; + +import java.util.*; + +/** + * Implementation of {@link Region}. This interface defines base contract for all L2 cache regions. + */ +public class HibernateRegion implements Region { + /** */ + protected final HibernateRegionFactory factory; + + /** */ + private final String name; + + /** Cache instance. */ + protected final GridCache<Object, Object> cache; + + /** Grid instance. */ + protected Ignite ignite; + + /** + * @param factory Region factory. + * @param name Region name. + * @param ignite Grid. + * @param cache Region cache. + */ + public HibernateRegion(HibernateRegionFactory factory, String name, Ignite ignite, + GridCache<Object, Object> cache) { + this.factory = factory; + this.name = name; + this.ignite = ignite; + this.cache = cache; + } + + /** {@inheritDoc} */ + @Override public String getName() { + return name; + } + + /** {@inheritDoc} */ + @Override public void destroy() throws CacheException { + // No-op. + } + + /** {@inheritDoc} */ + @Override public boolean contains(Object key) { + return cache.containsKey(key); + } + + /** {@inheritDoc} */ + @Override public long getSizeInMemory() { + return -1; + } + + /** {@inheritDoc} */ + @Override public long getElementCountInMemory() { + return cache.size(); + } + + /** {@inheritDoc} */ + @Override public long getElementCountOnDisk() { + return -1; + } + + /** {@inheritDoc} */ + @Override public Map toMap() { + return cache.toMap(); + } + + /** {@inheritDoc} */ + @Override public long nextTimestamp() { + return System.currentTimeMillis(); + } + + /** {@inheritDoc} */ + @Override public int getTimeout() { + return 0; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateRegionFactory.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateRegionFactory.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateRegionFactory.java new file mode 100644 index 0000000..8662518 --- /dev/null +++ b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateRegionFactory.java @@ -0,0 +1,231 @@ +/* + * 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.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.apache.ignite.internal.*; +import org.apache.ignite.internal.util.typedef.*; +import org.hibernate.cache.*; +import org.hibernate.cache.spi.*; +import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cfg.*; + +import java.util.*; + +import static org.hibernate.cache.spi.access.AccessType.*; + +/** + * Hibernate L2 cache region factory. + * <p> + * Following Hibernate settings should be specified to enable second level cache and to use this + * region factory for caching: + * <pre name="code" class="brush: xml; gutter: false;"> + * hibernate.cache.use_second_level_cache=true + * hibernate.cache.region.factory_class=org.apache.ignite.cache.hibernate.HibernateRegionFactory + * </pre> + * Note that before region factory is started you need to start properly configured Ignite node in the same JVM. + * For example to start Ignite node one of loader provided in {@code org.apache.ignite.grid.startup} package can be used. + * <p> + * Name of grid to be used for region factory must be specified as following Hibernate property: + * <pre name="code" class="brush: xml; gutter: false;"> + * org.apache.ignite.hibernate.grid_name=<grid name> + * </pre> + * Each Hibernate cache region must be associated with some {@link GridCache}, by default it is assumed that + * for each cache region there is a {@link GridCache} with the same name. Also it is possible to define + * region to cache mapping using properties with prefix {@code org.apache.ignite.hibernate.region_cache}. + * For example if for region with name "region1" cache with name "cache1" should be used then following + * Hibernate property should be specified: + * <pre name="code" class="brush: xml; gutter: false;"> + * org.apache.ignite.hibernate.region_cache.region1=cache1 + * </pre> + */ +public class HibernateRegionFactory implements RegionFactory { + /** */ + private static final long serialVersionUID = 0L; + + /** Hibernate L2 cache grid name property name. */ + public static final String GRID_NAME_PROPERTY = "org.apache.ignite.hibernate.grid_name"; + + /** Default cache property name. */ + public static final String DFLT_CACHE_NAME_PROPERTY = "org.apache.ignite.hibernate.default_cache"; + + /** Property prefix used to specify region name to cache name mapping. */ + public static final String REGION_CACHE_PROPERTY = "org.apache.ignite.hibernate.region_cache."; + + /** */ + public static final String DFLT_ACCESS_TYPE_PROPERTY = "org.apache.ignite.hibernate.default_access_type"; + + /** */ + public static final String GRID_CONFIG_PROPERTY = "org.apache.ignite.hibernate.grid_config"; + + /** Grid providing caches. */ + private Ignite ignite; + + /** Default cache. */ + private GridCache<Object, Object> dfltCache; + + /** Default region access type. */ + private AccessType dfltAccessType; + + /** Region name to cache name mapping. */ + private final Map<String, String> regionCaches = new HashMap<>(); + + /** Map needed to provide the same transaction context for different regions. */ + private final ThreadLocal threadLoc = new ThreadLocal(); + + /** {@inheritDoc} */ + @Override public void start(Settings settings, Properties props) throws CacheException { + String gridName = props.getProperty(GRID_NAME_PROPERTY); + + if (gridName != null) + ignite = G.ignite(gridName); + else { + String gridCfg = props.getProperty(GRID_CONFIG_PROPERTY); + + if (gridCfg == null) + throw new CacheException("Either grid name or path to grid configuration must be specified."); + + try { + ignite = G.start(gridCfg); + } + catch (IgniteException e) { + throw new CacheException(e); + } + } + + if (ignite == null) + throw new CacheException("Grid '" + gridName + "' for hibernate L2 cache is not started."); + + String accessType = props.getProperty(DFLT_ACCESS_TYPE_PROPERTY, NONSTRICT_READ_WRITE.name()); + + dfltAccessType = AccessType.valueOf(accessType); + + for (Map.Entry<Object, Object> prop : props.entrySet()) { + String key = prop.getKey().toString(); + + if (key.startsWith(REGION_CACHE_PROPERTY)) { + String regionName = key.substring(REGION_CACHE_PROPERTY.length()); + + String cacheName = prop.getValue().toString(); + + if (((IgniteKernal)ignite).cache(cacheName) == null) + throw new CacheException("Cache '" + cacheName + "' specified for region '" + regionName + "' " + + "is not configured."); + + regionCaches.put(regionName, cacheName); + } + } + + String dfltCacheName = props.getProperty(DFLT_CACHE_NAME_PROPERTY); + + if (dfltCacheName != null) { + dfltCache = ((IgniteKernal)ignite).cache(dfltCacheName); + + if (dfltCache == null) + throw new CacheException("Cache specified as default is not configured: " + dfltCacheName); + } + + IgniteLogger log = ignite.log().getLogger(HibernateRegionFactory.class); + + if (log.isDebugEnabled()) + log.debug("HibernateRegionFactory started [grid=" + gridName + ']'); + } + + /** {@inheritDoc} */ + @Override public void stop() { + } + + /** {@inheritDoc} */ + @Override public boolean isMinimalPutsEnabledByDefault() { + return false; + } + + /** {@inheritDoc} */ + @Override public AccessType getDefaultAccessType() { + return dfltAccessType; + } + + /** {@inheritDoc} */ + @Override public long nextTimestamp() { + return System.currentTimeMillis(); + } + + /** {@inheritDoc} */ + @Override public EntityRegion buildEntityRegion(String regionName, Properties props, CacheDataDescription metadata) + throws CacheException { + return new HibernateEntityRegion(this, regionName, ignite, regionCache(regionName), metadata); + } + + /** {@inheritDoc} */ + @Override public NaturalIdRegion buildNaturalIdRegion(String regionName, Properties props, + CacheDataDescription metadata) throws CacheException { + return new HibernateNaturalIdRegion(this, regionName, ignite, regionCache(regionName), metadata); + } + + /** {@inheritDoc} */ + @Override public CollectionRegion buildCollectionRegion(String regionName, Properties props, + CacheDataDescription metadata) throws CacheException { + return new HibernateCollectionRegion(this, regionName, ignite, regionCache(regionName), metadata); + } + + /** {@inheritDoc} */ + @Override public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties props) + throws CacheException { + return new HibernateQueryResultsRegion(this, regionName, ignite, regionCache(regionName)); + } + + /** {@inheritDoc} */ + @Override public TimestampsRegion buildTimestampsRegion(String regionName, Properties props) throws CacheException { + return new HibernateTimestampsRegion(this, regionName, ignite, regionCache(regionName)); + } + + /** + * Reuse same thread local for the same cache across different regions. + * + * @param cacheName Cache name. + * @return Thread local instance used to track updates done during one Hibernate transaction. + */ + ThreadLocal threadLocalForCache(String cacheName) { + return threadLoc; + } + + /** + * @param regionName L2 cache region name. + * @return Cache for given region. + * @throws CacheException If cache for given region is not configured. + */ + private GridCache<Object, Object> regionCache(String regionName) throws CacheException { + String cacheName = regionCaches.get(regionName); + + if (cacheName == null) { + if (dfltCache != null) + return dfltCache; + + cacheName = regionName; + } + + GridCache<Object, Object> cache = ((IgniteKernal)ignite).cache(cacheName); + + if (cache == null) + throw new CacheException("Cache '" + cacheName + "' for region '" + regionName + "' is not configured."); + + return cache; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateTimestampsRegion.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateTimestampsRegion.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateTimestampsRegion.java new file mode 100644 index 0000000..ce2252f --- /dev/null +++ b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateTimestampsRegion.java @@ -0,0 +1,40 @@ +/* + * 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.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.hibernate.cache.spi.*; + +/** + * Implementation of {@link TimestampsRegion}. This region is automatically created when query + * caching is enabled and it holds most recent updates timestamps to queryable tables. + * Name of timestamps region is {@code "org.hibernate.cache.spi.UpdateTimestampsCache"}. + */ +public class HibernateTimestampsRegion extends HibernateGeneralDataRegion implements TimestampsRegion { + /** + * @param factory Region factory. + * @param name Region name. + * @param ignite Grid. + * @param cache Region cache. + */ + public HibernateTimestampsRegion(HibernateRegionFactory factory, String name, + Ignite ignite, GridCache<Object, Object> cache) { + super(factory, name, ignite, cache); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5d694881/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateTransactionalAccessStrategy.java ---------------------------------------------------------------------- diff --git a/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateTransactionalAccessStrategy.java b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateTransactionalAccessStrategy.java new file mode 100644 index 0000000..0f8f1d9 --- /dev/null +++ b/modules/hibernate/src/main/java/org/apache/ignite/cache/hibernate/HibernateTransactionalAccessStrategy.java @@ -0,0 +1,139 @@ +/* + * 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.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.hibernate.cache.*; +import org.hibernate.cache.spi.access.*; +import org.jetbrains.annotations.*; + +/** + * Implementation of {@link AccessType#TRANSACTIONAL} cache access strategy. + * <p> + * It is supposed that this strategy is used in JTA environment and Hibernate and + * {@link GridCache} corresponding to the L2 cache region are configured to use the same transaction manager. + * <p> + * Configuration of L2 cache and per-entity cache access strategy can be set in the + * Hibernate configuration file: + * <pre name="code" class="xml"> + * <hibernate-configuration> + * <!-- Enable L2 cache. --> + * <property name="cache.use_second_level_cache">true</property> + * + * <!-- Use Ignite as L2 cache provider. --> + * <property name="cache.region.factory_class">org.apache.ignite.cache.hibernate.HibernateRegionFactory</property> + * + * <!-- Specify entity. --> + * <mapping class="com.example.Entity"/> + * + * <!-- Enable L2 cache with transactional access strategy for entity. --> + * <class-cache class="com.example.Entity" usage="transactional"/> + * </hibernate-configuration> + * </pre> + * Also cache access strategy can be set using annotations: + * <pre name="code" class="java"> + * @javax.persistence.Entity + * @javax.persistence.Cacheable + * @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) + * public class Entity { ... } + * </pre> + */ +public class HibernateTransactionalAccessStrategy extends HibernateAccessStrategyAdapter { + /** + * @param ignite Grid. + * @param cache Cache. + */ + public HibernateTransactionalAccessStrategy(Ignite ignite, GridCache<Object, Object> cache) { + super(ignite, cache); + } + + /** {@inheritDoc} */ + @Nullable @Override protected Object get(Object key) throws CacheException { + try { + return cache.get(key); + } + catch (IgniteCheckedException e) { + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Override protected void putFromLoad(Object key, Object val) throws CacheException { + try { + cache.putx(key, val); + } + catch (IgniteCheckedException e) { + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Override protected SoftLock lock(Object key) throws CacheException { + return null; + } + + /** {@inheritDoc} */ + @Override protected void unlock(Object key, SoftLock lock) throws CacheException { + // No-op. + } + + /** {@inheritDoc} */ + @Override protected boolean update(Object key, Object val) throws CacheException { + try { + cache.putx(key, val); + + return true; + } + catch (IgniteCheckedException e) { + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Override protected boolean afterUpdate(Object key, Object val, SoftLock lock) throws CacheException { + return false; + } + + /** {@inheritDoc} */ + @Override protected boolean insert(Object key, Object val) throws CacheException { + try { + cache.putx(key, val); + + return true; + } + catch (IgniteCheckedException e) { + throw new CacheException(e); + } + } + + /** {@inheritDoc} */ + @Override protected boolean afterInsert(Object key, Object val) throws CacheException { + return false; + } + + /** {@inheritDoc} */ + @Override protected void remove(Object key) throws CacheException { + try { + cache.removex(key); + } + catch (IgniteCheckedException e) { + throw new CacheException(e); + } + } +}