/* * Hibernate OGM, Domain model persistence for NoSQL datastores * * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.ogm.datastore.infinispanremote.impl.sequences; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.hibernate.ogm.datastore.infinispanremote.impl.InfinispanRemoteDatastoreProvider; import org.hibernate.ogm.datastore.infinispanremote.impl.protostream.OgmProtoStreamMarshaller; import org.hibernate.ogm.datastore.infinispanremote.impl.schema.SequenceTableDefinition; import org.hibernate.ogm.datastore.infinispanremote.logging.impl.Log; import org.hibernate.ogm.datastore.infinispanremote.logging.impl.LoggerFactory; import org.hibernate.ogm.dialect.spi.NextValueRequest; /** * Both IdSourceType.SEQUENCE and IdSourceType.TABLE are treated the same, essentially as a TABLE. * With Hot Rod mapping, a TABLE maps to a Cache, so we can store multiple "sequences" in the same * Cache by identifying each one by name. Each name is a key, so depending on perspective you * might consider these as a named SEQUENCE rather than a TABLE strategy. * * We don't write primitives to the Cache but wrap them in proper Protobuf mapped messages to * ensure to avoid conflicts with other mapped elements and to apply the column names of user's choice. * * The org.hibernate.ogm.datastore.infinispanremote.InfinispanRemoteDialect#supportsSequences * method returns 'false' so that we don't need a new Cache for each single sequence. * * See https://github.com/infinispan/infinispan/blob/master/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/ReplaceWithVersionConcurrencyTest.java * * @see org.hibernate.ogm.model.key.spi.IdSourceKeyMetadata.IdSourceType * @author Sanne Grinovero */ public class HotRodSequenceHandler { private static final Log log = LoggerFactory.getLogger(); private final InfinispanRemoteDatastoreProvider provider; private final ConcurrentMap<String,SequencesPerCache> sequencesPerCache = new ConcurrentHashMap<>(); private final Map<String, SequenceTableDefinition> idSchemaPerName; private final OgmProtoStreamMarshaller marshaller; public HotRodSequenceHandler( InfinispanRemoteDatastoreProvider infinispanRemoteDatastoreProvider, OgmProtoStreamMarshaller marshaller, Map<String, SequenceTableDefinition> idSchemaPerName) { this.provider = infinispanRemoteDatastoreProvider; this.idSchemaPerName = idSchemaPerName; this.marshaller = marshaller; } public Number getSequenceValue(NextValueRequest request) { final String cacheName = request.getKey().getMetadata().getName(); final SequencesPerCache sequencesSet = sequencesPerCache.computeIfAbsent( cacheName, ( k ) -> { SequenceTableDefinition sequenceTableDefinition = idSchemaPerName.get( cacheName ); if ( sequenceTableDefinition == null ) { throw log.valueRequestedForUnknownSequence( request.getKey().getTable(), request.getKey().getColumnValue() ); } return new SequencesPerCache( provider, sequenceTableDefinition, provider.getCache( cacheName ), marshaller ); } ); return sequencesSet.getSequenceValue( request ); } }