Implemented new row key for unique values.
Project: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/commit/d145eb4b Tree: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/tree/d145eb4b Diff: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/diff/d145eb4b Branch: refs/heads/two-dot-o-dev Commit: d145eb4b8e97c2eb4cb02fa568f357e5f8e7c5e2 Parents: 6e3fab6 Author: Todd Nine <[email protected]> Authored: Tue Mar 31 11:35:31 2015 -0600 Committer: Todd Nine <[email protected]> Committed: Tue Mar 31 11:35:31 2015 -0600 ---------------------------------------------------------------------- .../collection/guice/CollectionModule.java | 1 - .../UniqueValueSerializationStrategy.java | 10 +- .../impl/CollectionDataVersions.java | 10 + ...vccEntitySerializationStrategyProxyImpl.java | 2 + .../MvccLogEntrySerializationProxyImpl.java | 2 + .../MvccLogEntrySerializationStrategyImpl.java | 10 - .../serialization/impl/SerializationModule.java | 48 ++- .../UniqueValueSerializationStrategyImpl.java | 190 +++++----- ...iqueValueSerializationStrategyProxyImpl.java | 179 ++++++++++ .../UniqueValueSerializationStrategyV1Impl.java | 159 +++++++++ .../UniqueValueSerializationStrategyV2Impl.java | 139 ++++++++ ...niqueValueSerializationStrategyImplTest.java | 330 ------------------ ...niqueValueSerializationStrategyImplTest.java | 344 +++++++++++++++++++ ...ValueSerializationStrategyProxyImplTest.java | 100 ++++++ ...queValueSerializationStrategyV1ImplTest.java | 57 +++ ...queValueSerializationStrategyV2ImplTest.java | 58 ++++ 16 files changed, 1197 insertions(+), 442 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/d145eb4b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/guice/CollectionModule.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/guice/CollectionModule.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/guice/CollectionModule.java index eaf89ef..b256a44 100644 --- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/guice/CollectionModule.java +++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/guice/CollectionModule.java @@ -76,7 +76,6 @@ public abstract class CollectionModule extends AbstractModule { //bind this to our factory install( new GuicyFigModule( EntityCacheFig.class ) ); - bind( UniqueValueSerializationStrategy.class ).to( UniqueValueSerializationStrategyImpl.class ); bind( ChangeLogGenerator.class).to( ChangeLogGeneratorImpl.class); configureMigrationProvider(); http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/d145eb4b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/UniqueValueSerializationStrategy.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/UniqueValueSerializationStrategy.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/UniqueValueSerializationStrategy.java index 71af460..3645107 100644 --- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/UniqueValueSerializationStrategy.java +++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/UniqueValueSerializationStrategy.java @@ -21,6 +21,7 @@ package org.apache.usergrid.persistence.collection.serialization; import java.util.Collection; import java.util.Iterator; +import org.apache.usergrid.persistence.core.migration.data.VersionedData; import org.apache.usergrid.persistence.core.migration.schema.Migration; import org.apache.usergrid.persistence.core.scope.ApplicationScope; import org.apache.usergrid.persistence.model.entity.Id; @@ -34,7 +35,7 @@ import com.netflix.astyanax.model.ConsistencyLevel; /** * Reads and writes to UniqueValues column family. */ -public interface UniqueValueSerializationStrategy extends Migration { +public interface UniqueValueSerializationStrategy extends Migration, VersionedData { /** @@ -73,14 +74,14 @@ public interface UniqueValueSerializationStrategy extends Migration { /** * Load UniqueValue that matches field from collection or null if that value does not exist. * - * @param colScope Collection scope in which to look for field name/value + * @param applicationScope Collection scope in which to look for field name/value * @param consistencyLevel Consistency level of query * @param type The type the unique value exists within * @param fields Field name/value to search for * @return UniqueValueSet containing fields from the collection that exist in cassandra * @throws ConnectionException on error connecting to Cassandra */ - UniqueValueSet load( ApplicationScope colScope, ConsistencyLevel consistencyLevel, String type, + UniqueValueSet load( ApplicationScope applicationScope, ConsistencyLevel consistencyLevel, String type, Collection<Field> fields ) throws ConnectionException; @@ -98,10 +99,11 @@ public interface UniqueValueSerializationStrategy extends Migration { /** * Delete the specified Unique Value from Cassandra. * + * @param applicationScope The scope of the application * @param uniqueValue Object to be deleted. * @return MutatationBatch that encapsulates operation, caller may or may not execute. */ - MutationBatch delete( ApplicationScope scope, UniqueValue uniqueValue ); + MutationBatch delete( ApplicationScope applicationScope, UniqueValue uniqueValue ); } http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/d145eb4b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/CollectionDataVersions.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/CollectionDataVersions.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/CollectionDataVersions.java index 84028d6..b1ce98b 100644 --- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/CollectionDataVersions.java +++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/CollectionDataVersions.java @@ -28,8 +28,18 @@ package org.apache.usergrid.persistence.collection.serialization.impl; * Versions of data as they exist across our system */ public enum CollectionDataVersions{ + /** + * The initial released version + */ INITIAL(0), + /** + * The version where serialization was changed from using a short in the composite to an integer + */ BUFFER_SHORT_FIX(1), + + /** + * The change where we move unique field versions to their own CF, and then only store our latest object version + */ LOG_REMOVAL(2); private final int version; http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/d145eb4b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccEntitySerializationStrategyProxyImpl.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccEntitySerializationStrategyProxyImpl.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccEntitySerializationStrategyProxyImpl.java index bb143a4..b45f68b 100644 --- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccEntitySerializationStrategyProxyImpl.java +++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccEntitySerializationStrategyProxyImpl.java @@ -35,6 +35,7 @@ import org.apache.usergrid.persistence.model.entity.Id; import com.google.common.base.Optional; import com.google.inject.Inject; +import com.google.inject.Singleton; import com.netflix.astyanax.Keyspace; import com.netflix.astyanax.MutationBatch; @@ -44,6 +45,7 @@ import com.netflix.astyanax.MutationBatch; * migration data goes to both sources and is read from the old source. After the upgrade completes, * it will be available from the new source */ +@Singleton public class MvccEntitySerializationStrategyProxyImpl implements MvccEntitySerializationStrategy { http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/d145eb4b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccLogEntrySerializationProxyImpl.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccLogEntrySerializationProxyImpl.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccLogEntrySerializationProxyImpl.java index e0f6f03..81c0248 100644 --- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccLogEntrySerializationProxyImpl.java +++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccLogEntrySerializationProxyImpl.java @@ -37,6 +37,7 @@ import org.apache.usergrid.persistence.core.scope.ApplicationScope; import org.apache.usergrid.persistence.model.entity.Id; import com.google.inject.Inject; +import com.google.inject.Singleton; import com.netflix.astyanax.Keyspace; import com.netflix.astyanax.MutationBatch; @@ -44,6 +45,7 @@ import com.netflix.astyanax.MutationBatch; /** * The proxy for performing log entry serialization */ +@Singleton public class MvccLogEntrySerializationProxyImpl implements MvccLogEntrySerializationStrategy { protected final Keyspace keyspace; http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/d145eb4b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccLogEntrySerializationStrategyImpl.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccLogEntrySerializationStrategyImpl.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccLogEntrySerializationStrategyImpl.java index d6baa3c..76e9dba 100644 --- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccLogEntrySerializationStrategyImpl.java +++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/MvccLogEntrySerializationStrategyImpl.java @@ -273,18 +273,8 @@ public abstract class MvccLogEntrySerializationStrategyImpl<K> implements MvccLo LOG.debug( "Writing version with timestamp '{}'", timestamp ); final Id applicationId = collectionScope.getApplication(); - final Id ownerId = applicationId; - final String collectionName = LegacyScopeUtils.getCollectionScopeNameFromEntityType( entityId.getType() ); final ScopedRowKey<K> key = createKey( applicationId, entityId ); -// -// final CollectionPrefixedKey<Id> collectionPrefixedKey = -// new CollectionPrefixedKey<>( collectionName, ownerId, entityId ); -// -// -// final ScopedRowKey<CollectionPrefixedKey<Id>> rowKey = -// ScopedRowKey.fromKey( applicationId, collectionPrefixedKey ); - op.doOp( batch.withRow( CF_ENTITY_LOG, key ) ); http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/d145eb4b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/SerializationModule.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/SerializationModule.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/SerializationModule.java index fa1991a..bd2728b 100644 --- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/SerializationModule.java +++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/SerializationModule.java @@ -67,21 +67,28 @@ public class SerializationModule extends AbstractModule { bind( MvccLogEntrySerializationStrategyV2Impl.class ); - bind( MvccLogEntrySerializationStrategy.class ) - .to( MvccLogEntrySerializationProxyImpl.class ); + bind( MvccLogEntrySerializationStrategy.class ).to( MvccLogEntrySerializationProxyImpl.class ); - bind( UniqueValueSerializationStrategy.class ).to( UniqueValueSerializationStrategyImpl.class ); + bind( UniqueValueSerializationStrategyV1Impl.class ); + bind(UniqueValueSerializationStrategyV2Impl.class); + + bind( UniqueValueSerializationStrategy.class ).to( UniqueValueSerializationStrategyProxyImpl.class ); //do multibindings for migrations Multibinder<Migration> migrationBinder = Multibinder.newSetBinder( binder(), Migration.class ); + //entity serialization versions migrationBinder.addBinding().to( Key.get( MvccEntitySerializationStrategyV1Impl.class ) ); migrationBinder.addBinding().to( Key.get( MvccEntitySerializationStrategyV2Impl.class ) ); migrationBinder.addBinding().to( Key.get( MvccEntitySerializationStrategyV3Impl.class ) ); + + //log serialization versions migrationBinder.addBinding().to( Key.get( MvccLogEntrySerializationStrategyV1Impl.class ) ); migrationBinder.addBinding().to( Key.get( MvccLogEntrySerializationStrategyV2Impl.class ) ); - migrationBinder.addBinding().to( Key.get( UniqueValueSerializationStrategy.class ) ); + //unique value serialization versions + migrationBinder.addBinding().to( Key.get( UniqueValueSerializationStrategyV1Impl.class ) ); + migrationBinder.addBinding().to( Key.get( UniqueValueSerializationStrategyV2Impl.class ) ); //bind our settings as an eager singleton so it's checked on startup @@ -123,7 +130,7 @@ public class SerializationModule extends AbstractModule { //note that we MUST migrate to v3 before our next migration, if v4 and v5 is implemented we will need a // v3->v5 and a v4->v5 set MigrationRelationship<MvccEntitySerializationStrategy> current = - new MigrationRelationship<MvccEntitySerializationStrategy>( v3, v3 ); + new MigrationRelationship<>( v3, v3 ); //now create our set of versions @@ -151,7 +158,7 @@ public class SerializationModule extends AbstractModule { //note that we MUST migrate to v3 before our next migration, if v4 and v5 is implemented we will need a // v3->v5 and a v4->v5 set MigrationRelationship<MvccLogEntrySerializationStrategy> current = - new MigrationRelationship<MvccLogEntrySerializationStrategy>( v2, v2 ); + new MigrationRelationship<>( v2, v2 ); //now create our set of versions @@ -160,4 +167,33 @@ public class SerializationModule extends AbstractModule { return set; } + + + + /** + * Configure via explicit declaration the migration path we can follow + */ + @Singleton + @Inject + @Provides + public VersionedMigrationSet<UniqueValueSerializationStrategy> getVersions( + final UniqueValueSerializationStrategyV1Impl v1, final UniqueValueSerializationStrategyV2Impl v2) { + + + //we must perform a migration from v1 to v3 in order to maintain consistency + MigrationRelationship<UniqueValueSerializationStrategy> v1Tov2 = new MigrationRelationship<>( v1, v2 ); + + + //note that we MUST migrate to v3 before our next migration, if v4 and v5 is implemented we will need a + // v3->v5 and a v4->v5 set + MigrationRelationship<UniqueValueSerializationStrategy> current = + new MigrationRelationship<>( v2, v2 ); + + + //now create our set of versions + VersionedMigrationSet<UniqueValueSerializationStrategy> set = + new VersionedMigrationSet<>( v1Tov2, current ); + + return set; + } } http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/d145eb4b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyImpl.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyImpl.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyImpl.java index bd35c7a..a1fb4cc 100644 --- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyImpl.java +++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyImpl.java @@ -39,7 +39,6 @@ import org.apache.usergrid.persistence.core.astyanax.CassandraFig; import org.apache.usergrid.persistence.core.astyanax.ColumnNameIterator; import org.apache.usergrid.persistence.core.astyanax.ColumnParser; import org.apache.usergrid.persistence.core.astyanax.ColumnTypes; -import org.apache.usergrid.persistence.core.astyanax.IdRowCompositeSerializer; import org.apache.usergrid.persistence.core.astyanax.MultiTennantColumnFamily; import org.apache.usergrid.persistence.core.astyanax.MultiTennantColumnFamilyDefinition; import org.apache.usergrid.persistence.core.astyanax.ScopedRowKey; @@ -64,53 +63,42 @@ import com.netflix.astyanax.util.RangeBuilder; /** * Reads and writes to UniqueValues column family. */ -public class UniqueValueSerializationStrategyImpl implements UniqueValueSerializationStrategy { +public abstract class UniqueValueSerializationStrategyImpl<FieldKey, EntityKey> + implements UniqueValueSerializationStrategy { private static final Logger log = LoggerFactory.getLogger( UniqueValueSerializationStrategyImpl.class ); - private static final CollectionScopedRowKeySerializer<Field> ROW_KEY_SER = - new CollectionScopedRowKeySerializer<>( UniqueFieldRowKeySerializer.get() ); + private final MultiTennantColumnFamily<ScopedRowKey<FieldKey>, EntityVersion> + CF_UNIQUE_VALUES; - private static final EntityVersionSerializer ENTITY_VERSION_SER = new EntityVersionSerializer(); - private static final MultiTennantColumnFamily<ScopedRowKey<CollectionPrefixedKey<Field>>, EntityVersion> - CF_UNIQUE_VALUES = new MultiTennantColumnFamily<>( "Unique_Values", ROW_KEY_SER, ENTITY_VERSION_SER ); - - - - private static final IdRowCompositeSerializer ID_SER = IdRowCompositeSerializer.get(); - - - private static final CollectionScopedRowKeySerializer<Id> ENTITY_ROW_KEY_SER = - new CollectionScopedRowKeySerializer<>( ID_SER ); - - - - private static final MultiTennantColumnFamily<ScopedRowKey<CollectionPrefixedKey<Id>>, UniqueFieldEntry> - CF_ENTITY_UNIQUE_VALUES = - new MultiTennantColumnFamily<>( "Entity_Unique_Values", ENTITY_ROW_KEY_SER, UniqueFieldEntrySerializer.get() ); + private final MultiTennantColumnFamily<ScopedRowKey<EntityKey>, UniqueFieldEntry> + CF_ENTITY_UNIQUE_VALUE_LOG ; public static final int COL_VALUE = 0x0; private final SerializationFig serializationFig; protected final Keyspace keyspace; - private final CassandraFig cassandraFig; - + private final CassandraFig cassandraFig; /** * Construct serialization strategy for keyspace. * * @param keyspace Keyspace in which to store Unique Values. - * @param serializationFig + * @param cassandraFig The cassandra configuration + * @param serializationFig The serialization configuration */ - @Inject - public UniqueValueSerializationStrategyImpl( final Keyspace keyspace, final CassandraFig cassandraFig, final SerializationFig serializationFig ) { + public UniqueValueSerializationStrategyImpl( final Keyspace keyspace, final CassandraFig cassandraFig, + final SerializationFig serializationFig ) { this.keyspace = keyspace; this.cassandraFig = cassandraFig; this.serializationFig = serializationFig; + + CF_UNIQUE_VALUES = getUniqueValuesCF(); + CF_ENTITY_UNIQUE_VALUE_LOG = getEntityUniqueLogCF(); } @@ -131,7 +119,7 @@ public class UniqueValueSerializationStrategyImpl implements UniqueValueSerializ final EntityVersion ev = new EntityVersion( entityId, entityVersion ); final UniqueFieldEntry uniqueFieldEntry = new UniqueFieldEntry( entityVersion, field ); - return doWrite( collectionScope, value, new UniqueValueSerializationStrategyImpl.RowOp() { + return doWrite( collectionScope, value, new RowOp() { @Override public void doLookup( final ColumnListMutation<EntityVersion> colMutation ) { @@ -148,7 +136,8 @@ public class UniqueValueSerializationStrategyImpl implements UniqueValueSerializ @Override - public MutationBatch write( final ApplicationScope collectionScope, final UniqueValue value, final int timeToLive ) { + public MutationBatch write( final ApplicationScope collectionScope, final UniqueValue value, + final int timeToLive ) { Preconditions.checkNotNull( value, "value is required" ); Preconditions.checkArgument( timeToLive > 0, "timeToLive must be greater than 0 is required" ); @@ -163,7 +152,7 @@ public class UniqueValueSerializationStrategyImpl implements UniqueValueSerializ final EntityVersion ev = new EntityVersion( entityId, entityVersion ); final UniqueFieldEntry uniqueFieldEntry = new UniqueFieldEntry( entityVersion, field ); - return doWrite( collectionScope, value, new UniqueValueSerializationStrategyImpl.RowOp() { + return doWrite( collectionScope, value, new RowOp() { @Override public void doLookup( final ColumnListMutation<EntityVersion> colMutation ) { @@ -198,7 +187,7 @@ public class UniqueValueSerializationStrategyImpl implements UniqueValueSerializ final EntityVersion ev = new EntityVersion( entityId, entityVersion ); final UniqueFieldEntry uniqueFieldEntry = new UniqueFieldEntry( entityVersion, field ); - return doWrite( scope, value, new UniqueValueSerializationStrategyImpl.RowOp() { + return doWrite( scope, value, new RowOp() { @Override public void doLookup( final ColumnListMutation<EntityVersion> colMutation ) { @@ -225,32 +214,24 @@ public class UniqueValueSerializationStrategyImpl implements UniqueValueSerializ final MutationBatch batch = keyspace.prepareMutationBatch(); final Id applicationId = applicationScope.getApplication(); - final Id uniqueValueId = uniqueValue.getEntityId(); - final String collectionName = LegacyScopeUtils.getCollectionScopeNameFromEntityType( uniqueValueId.getType() ); + final FieldKey fieldKey = createUniqueValueKey( applicationId, uniqueValue.getEntityId().getType(), uniqueValue.getField() ); - final CollectionPrefixedKey<Field> uniquePrefixedKey = - new CollectionPrefixedKey<>( collectionName, applicationId, uniqueValue.getField() ); + op.doLookup( batch.withRow( CF_UNIQUE_VALUES, ScopedRowKey.fromKey( applicationId, fieldKey ) ) ); - op.doLookup( batch - .withRow( CF_UNIQUE_VALUES, ScopedRowKey.fromKey( applicationId, uniquePrefixedKey ) ) ); + final EntityKey entityKey = createEntityUniqueLogKey( applicationId, uniqueValue.getEntityId() ); - final Id ownerId = applicationId; + op.doLog( batch.withRow( CF_ENTITY_UNIQUE_VALUE_LOG, + ScopedRowKey.fromKey( applicationId, entityKey ) ) ); - final CollectionPrefixedKey<Id> collectionPrefixedEntityKey = - new CollectionPrefixedKey<>( collectionName, ownerId, uniqueValue.getEntityId() ); - - op.doLog( batch.withRow( CF_ENTITY_UNIQUE_VALUES, - ScopedRowKey.fromKey( applicationId, collectionPrefixedEntityKey ) ) ); - - - if(log.isDebugEnabled()) { - log.debug( "Writing unique value collectionScope={} id={} version={} name={} value={} ttl={} ", new - Object[] { - collectionName, uniqueValueId, uniqueValue.getEntityVersion(), uniqueValue.getField().getName(), uniqueValue.getField().getValue() + if ( log.isDebugEnabled() ) { + log.debug( "Writing unique value version={} name={} value={} ", + new Object[] { + uniqueValue.getEntityVersion(), uniqueValue.getField().getName(), + uniqueValue.getField().getValue() } ); } @@ -259,64 +240,64 @@ public class UniqueValueSerializationStrategyImpl implements UniqueValueSerializ } - @Override - public UniqueValueSet load(final ApplicationScope colScope, final String type, final Collection<Field> fields ) throws ConnectionException{ - return load(colScope,ConsistencyLevel.valueOf(cassandraFig.getReadCL()), type, fields); + public UniqueValueSet load( final ApplicationScope colScope, final String type, final Collection<Field> fields ) + throws ConnectionException { + return load( colScope, ConsistencyLevel.valueOf( cassandraFig.getReadCL() ), type, fields ); } + @Override - public UniqueValueSet load(final ApplicationScope appScope, final ConsistencyLevel consistencyLevel, final String type, final Collection<Field> fields ) - throws ConnectionException { + public UniqueValueSet load( final ApplicationScope appScope, final ConsistencyLevel consistencyLevel, + final String type, final Collection<Field> fields ) throws ConnectionException { Preconditions.checkNotNull( fields, "fields are required" ); Preconditions.checkArgument( fields.size() > 0, "More than 1 field must be specified" ); - final List<ScopedRowKey<CollectionPrefixedKey<Field>>> keys = new ArrayList<>( fields.size() ); + final List<ScopedRowKey<FieldKey>> keys = new ArrayList<>( fields.size() ); final Id applicationId = appScope.getApplication(); - final Id ownerId = appScope.getApplication(); - final String collectionName = LegacyScopeUtils.getCollectionScopeNameFromEntityType( type ); for ( Field field : fields ) { - final CollectionPrefixedKey<Field> collectionPrefixedKey = new CollectionPrefixedKey<>( collectionName, ownerId, field ); + final FieldKey key = createUniqueValueKey( applicationId, type, field ); - final ScopedRowKey<CollectionPrefixedKey<Field>> rowKey = ScopedRowKey.fromKey(applicationId, collectionPrefixedKey ); + final ScopedRowKey<FieldKey> rowKey = + ScopedRowKey.fromKey( applicationId, key ); keys.add( rowKey ); } final UniqueValueSetImpl uniqueValueSet = new UniqueValueSetImpl( fields.size() ); - Iterator<Row<ScopedRowKey<CollectionPrefixedKey<Field>>, EntityVersion>> results = - keyspace.prepareQuery( CF_UNIQUE_VALUES ).setConsistencyLevel(consistencyLevel).getKeySlice( keys ) - .withColumnRange( new RangeBuilder().setLimit( 1 ).build() ).execute().getResult().iterator(); + Iterator<Row<ScopedRowKey<FieldKey>, EntityVersion>> results = + keyspace.prepareQuery( CF_UNIQUE_VALUES ).setConsistencyLevel( consistencyLevel ).getKeySlice( keys ) + .withColumnRange( new RangeBuilder().setLimit( 1 ).build() ).execute().getResult().iterator(); while ( results.hasNext() ) { - final Row<ScopedRowKey<CollectionPrefixedKey<Field>>, EntityVersion> unique = results.next(); + final Row<ScopedRowKey<FieldKey>, EntityVersion> unique = results.next(); - final Field field = unique.getKey().getKey().getSubKey(); + final Field field = parseRowKey( unique.getKey() ); final Iterator<Column<EntityVersion>> columnList = unique.getColumns().iterator(); //sanity check, nothing to do, skip it - if ( !columnList.hasNext()) { + if ( !columnList.hasNext() ) { continue; } final EntityVersion entityVersion = columnList.next().getName(); - final UniqueValueImpl uniqueValue = new UniqueValueImpl(field, entityVersion.getEntityId(), - entityVersion.getEntityVersion() ); + final UniqueValueImpl uniqueValue = + new UniqueValueImpl( field, entityVersion.getEntityId(), entityVersion.getEntityVersion() ); uniqueValueSet.addValue( uniqueValue ); } @@ -327,53 +308,44 @@ public class UniqueValueSerializationStrategyImpl implements UniqueValueSerializ @Override public Iterator<UniqueValue> getAllUniqueFields( final ApplicationScope collectionScope, final Id entityId ) { - - Preconditions.checkNotNull( collectionScope, "collectionScope is required" ); Preconditions.checkNotNull( entityId, "entity id is required" ); final Id applicationId = collectionScope.getApplication(); - final Id ownerId = applicationId; - final String collectionName = LegacyScopeUtils.getCollectionScopeNameFromEntityType( entityId.getType() ); - final CollectionPrefixedKey<Id> collectionPrefixedKey = - new CollectionPrefixedKey<>( collectionName, ownerId, entityId ); + final EntityKey entityKey = createEntityUniqueLogKey( applicationId, entityId ); - final ScopedRowKey<CollectionPrefixedKey<Id>> rowKey = - ScopedRowKey.fromKey( applicationId, collectionPrefixedKey ); + final ScopedRowKey<EntityKey> rowKey = + ScopedRowKey.fromKey( applicationId, entityKey ); - RowQuery<ScopedRowKey<CollectionPrefixedKey<Id>>, UniqueFieldEntry> query = - keyspace.prepareQuery( CF_ENTITY_UNIQUE_VALUES ).getKey( rowKey ).withColumnRange( - ( UniqueFieldEntry ) null, null, false, serializationFig.getBufferSize() ); + RowQuery<ScopedRowKey<EntityKey>, UniqueFieldEntry> query = + keyspace.prepareQuery( CF_ENTITY_UNIQUE_VALUE_LOG ).getKey( rowKey ) + .withColumnRange( ( UniqueFieldEntry ) null, null, false, serializationFig.getBufferSize() ); return new ColumnNameIterator( query, new UniqueEntryParser( entityId ), false ); - } /** * Simple callback to perform puts and deletes with a common row setup code */ - private static interface RowOp { + private interface RowOp { /** * Execute the mutation into the lookup CF_UNIQUE_VALUES row - * @param colMutation */ void doLookup( ColumnListMutation<EntityVersion> colMutation ); /** * Execute the mutation into the lCF_ENTITY_UNIQUE_VALUESLUE row - * @param colMutation */ - void doLog( ColumnListMutation<UniqueFieldEntry> colMutation); + void doLog( ColumnListMutation<UniqueFieldEntry> colMutation ); } - /** * Converts raw columns to the expected output */ @@ -394,20 +366,56 @@ public class UniqueValueSerializationStrategyImpl implements UniqueValueSerializ } - @Override public Collection<MultiTennantColumnFamilyDefinition> getColumnFamilies() { final MultiTennantColumnFamilyDefinition uniqueLookupCF = - new MultiTennantColumnFamilyDefinition( CF_UNIQUE_VALUES, BytesType.class.getSimpleName(), - ColumnTypes.DYNAMIC_COMPOSITE_TYPE, BytesType.class.getSimpleName(), - MultiTennantColumnFamilyDefinition.CacheOption.KEYS ); + new MultiTennantColumnFamilyDefinition( CF_UNIQUE_VALUES, BytesType.class.getSimpleName(), + ColumnTypes.DYNAMIC_COMPOSITE_TYPE, BytesType.class.getSimpleName(), + MultiTennantColumnFamilyDefinition.CacheOption.KEYS ); final MultiTennantColumnFamilyDefinition uniqueLogCF = - new MultiTennantColumnFamilyDefinition( CF_ENTITY_UNIQUE_VALUES, BytesType.class.getSimpleName(), - ColumnTypes.DYNAMIC_COMPOSITE_TYPE, BytesType.class.getSimpleName(), - MultiTennantColumnFamilyDefinition.CacheOption.KEYS ); + new MultiTennantColumnFamilyDefinition( CF_ENTITY_UNIQUE_VALUE_LOG, BytesType.class.getSimpleName(), + ColumnTypes.DYNAMIC_COMPOSITE_TYPE, BytesType.class.getSimpleName(), + MultiTennantColumnFamilyDefinition.CacheOption.KEYS ); - return Arrays.asList( uniqueLookupCF, uniqueLogCF); + return Arrays.asList( uniqueLookupCF, uniqueLogCF ); } + + + /** + * Get the column family for the unique fields + */ + protected abstract MultiTennantColumnFamily<ScopedRowKey<FieldKey>, EntityVersion> getUniqueValuesCF(); + + + /** + * Generate a key that is compatible with the column family + * + * @param applicationId The applicationId + * @param type The type in the field + * @param field The field we're creating the key for + */ + protected abstract FieldKey createUniqueValueKey(final Id applicationId, final String type, final Field field ); + + /** + * Parse the row key into the field + * @param rowKey + * @return + */ + protected abstract Field parseRowKey(final ScopedRowKey<FieldKey> rowKey); + + + /** + * Get the column family for the unique field CF + */ + protected abstract MultiTennantColumnFamily<ScopedRowKey<EntityKey>, UniqueFieldEntry> getEntityUniqueLogCF(); + + /** + * Generate a key that is compatible with the column family + * + * @param applicationId The applicationId + * @param uniqueValueId The uniqueValue + */ + protected abstract EntityKey createEntityUniqueLogKey(final Id applicationId, final Id uniqueValueId ); } http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/d145eb4b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyProxyImpl.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyProxyImpl.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyProxyImpl.java new file mode 100644 index 0000000..3b15142 --- /dev/null +++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyProxyImpl.java @@ -0,0 +1,179 @@ +/* + * 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.usergrid.persistence.collection.serialization.impl; + + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; + +import org.apache.usergrid.persistence.collection.serialization.UniqueValue; +import org.apache.usergrid.persistence.collection.serialization.UniqueValueSerializationStrategy; +import org.apache.usergrid.persistence.collection.serialization.UniqueValueSet; +import org.apache.usergrid.persistence.collection.serialization.impl.migration.CollectionMigrationPlugin; +import org.apache.usergrid.persistence.core.astyanax.MultiTennantColumnFamilyDefinition; +import org.apache.usergrid.persistence.core.migration.data.MigrationInfoCache; +import org.apache.usergrid.persistence.core.migration.data.MigrationRelationship; +import org.apache.usergrid.persistence.core.migration.data.VersionedMigrationSet; +import org.apache.usergrid.persistence.core.scope.ApplicationScope; +import org.apache.usergrid.persistence.model.entity.Id; +import org.apache.usergrid.persistence.model.field.Field; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.netflix.astyanax.Keyspace; +import com.netflix.astyanax.MutationBatch; +import com.netflix.astyanax.connectionpool.exceptions.ConnectionException; +import com.netflix.astyanax.model.ConsistencyLevel; + + +@Singleton +public class UniqueValueSerializationStrategyProxyImpl implements UniqueValueSerializationStrategy { + + + protected final Keyspace keyspace; + private final VersionedMigrationSet<UniqueValueSerializationStrategy> versions; + private final MigrationInfoCache migrationInfoCache; + + + @Inject + public UniqueValueSerializationStrategyProxyImpl( final Keyspace keyspace, + final VersionedMigrationSet<UniqueValueSerializationStrategy> + allVersions, + final MigrationInfoCache migrationInfoCache ) { + + this.keyspace = keyspace; + this.migrationInfoCache = migrationInfoCache; + this.versions = allVersions; + } + + + @Override + public MutationBatch write( final ApplicationScope applicationScope, final UniqueValue uniqueValue ) { + final MigrationRelationship<UniqueValueSerializationStrategy> migration = getMigrationRelationShip(); + + if ( migration.needsMigration() ) { + final MutationBatch aggregateBatch = keyspace.prepareMutationBatch(); + + aggregateBatch.mergeShallow( migration.from.write( applicationScope, uniqueValue ) ); + aggregateBatch.mergeShallow( migration.to.write( applicationScope, uniqueValue ) ); + + return aggregateBatch; + } + + return migration.to.write( applicationScope, uniqueValue ); + } + + + @Override + public MutationBatch write( final ApplicationScope applicationScope, final UniqueValue uniqueValue, + final int timeToLive ) { + final MigrationRelationship<UniqueValueSerializationStrategy> migration = getMigrationRelationShip(); + + if ( migration.needsMigration() ) { + final MutationBatch aggregateBatch = keyspace.prepareMutationBatch(); + + aggregateBatch.mergeShallow( migration.from.write( applicationScope, uniqueValue, timeToLive ) ); + aggregateBatch.mergeShallow( migration.to.write( applicationScope, uniqueValue, timeToLive ) ); + + return aggregateBatch; + } + + return migration.to.write( applicationScope, uniqueValue, timeToLive ); + } + + + @Override + public UniqueValueSet load( final ApplicationScope applicationScope, final String type, + final Collection<Field> fields ) throws ConnectionException { + + final MigrationRelationship<UniqueValueSerializationStrategy> migration = getMigrationRelationShip(); + + if ( migration.needsMigration() ) { + return migration.from.load( applicationScope, type, fields ); + } + + return migration.to.load( applicationScope, type, fields ); + } + + + @Override + public UniqueValueSet load( final ApplicationScope applicationScope, final ConsistencyLevel consistencyLevel, + final String type, final Collection<Field> fields ) throws ConnectionException { + + final MigrationRelationship<UniqueValueSerializationStrategy> migration = getMigrationRelationShip(); + + if ( migration.needsMigration() ) { + return migration.from.load( applicationScope, type, fields ); + } + + return migration.to.load( applicationScope, type, fields ); + } + + + @Override + public Iterator<UniqueValue> getAllUniqueFields( final ApplicationScope applicationScope, final Id entityId ) { + final MigrationRelationship<UniqueValueSerializationStrategy> migration = getMigrationRelationShip(); + + if ( migration.needsMigration() ) { + return migration.from.getAllUniqueFields( applicationScope, entityId ); + } + + return migration.to.getAllUniqueFields( applicationScope, entityId ); + } + + + @Override + public MutationBatch delete( final ApplicationScope applicationScope, final UniqueValue uniqueValue ) { + final MigrationRelationship<UniqueValueSerializationStrategy> migration = getMigrationRelationShip(); + + if ( migration.needsMigration() ) { + final MutationBatch aggregateBatch = keyspace.prepareMutationBatch(); + + aggregateBatch.mergeShallow( migration.from.delete( applicationScope, uniqueValue ) ); + aggregateBatch.mergeShallow( migration.to.delete( applicationScope, uniqueValue ) ); + + return aggregateBatch; + } + + return migration.to.delete( applicationScope, uniqueValue ); + } + + + /** + * Return true if we're on an old version + */ + private MigrationRelationship<UniqueValueSerializationStrategy> getMigrationRelationShip() { + return this.versions + .getMigrationRelationship( migrationInfoCache.getVersion( CollectionMigrationPlugin.PLUGIN_NAME ) ); + } + + + @Override + public Collection<MultiTennantColumnFamilyDefinition> getColumnFamilies() { + return Collections.emptyList(); + } + + + @Override + public int getImplementationVersion() { + throw new UnsupportedOperationException( "Not supported in the proxy" ); + } +} http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/d145eb4b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyV1Impl.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyV1Impl.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyV1Impl.java new file mode 100644 index 0000000..6551f5d --- /dev/null +++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyV1Impl.java @@ -0,0 +1,159 @@ +/* + * 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.usergrid.persistence.collection.serialization.impl; + + +import java.util.Arrays; +import java.util.Collection; + +import org.apache.cassandra.db.marshal.BytesType; + +import org.apache.usergrid.persistence.collection.serialization.SerializationFig; +import org.apache.usergrid.persistence.collection.serialization.UniqueValue; +import org.apache.usergrid.persistence.collection.serialization.impl.util.LegacyScopeUtils; +import org.apache.usergrid.persistence.core.astyanax.CassandraFig; +import org.apache.usergrid.persistence.core.astyanax.ColumnTypes; +import org.apache.usergrid.persistence.core.astyanax.IdRowCompositeSerializer; +import org.apache.usergrid.persistence.core.astyanax.MultiTennantColumnFamily; +import org.apache.usergrid.persistence.core.astyanax.MultiTennantColumnFamilyDefinition; +import org.apache.usergrid.persistence.core.astyanax.ScopedRowKey; +import org.apache.usergrid.persistence.model.entity.Id; +import org.apache.usergrid.persistence.model.field.Field; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.netflix.astyanax.Keyspace; + + +/** + * V1 impl with unique value serialization strategy with the collection scope + */ +@Singleton +public class UniqueValueSerializationStrategyV1Impl extends UniqueValueSerializationStrategyImpl<CollectionPrefixedKey<Field>, CollectionPrefixedKey<Id>> { + + + private static final CollectionScopedRowKeySerializer<Field> ROW_KEY_SER = + new CollectionScopedRowKeySerializer<>( UniqueFieldRowKeySerializer.get() ); + + private static final EntityVersionSerializer ENTITY_VERSION_SER = new EntityVersionSerializer(); + + private static final MultiTennantColumnFamily<ScopedRowKey<CollectionPrefixedKey<Field>>, EntityVersion> + CF_UNIQUE_VALUES = new MultiTennantColumnFamily<>( "Unique_Values", ROW_KEY_SER, ENTITY_VERSION_SER ); + + + private static final IdRowCompositeSerializer ID_SER = IdRowCompositeSerializer.get(); + + + private static final CollectionScopedRowKeySerializer<Id> ENTITY_ROW_KEY_SER = + new CollectionScopedRowKeySerializer<>( ID_SER ); + + + private static final MultiTennantColumnFamily<ScopedRowKey<CollectionPrefixedKey<Id>>, UniqueFieldEntry> + CF_ENTITY_UNIQUE_VALUE_LOG = + new MultiTennantColumnFamily<>( "Entity_Unique_Values", ENTITY_ROW_KEY_SER, UniqueFieldEntrySerializer.get() ); + + + /** + * Construct serialization strategy for keyspace. + * + * @param keyspace Keyspace in which to store Unique Values. + * @param cassandraFig The cassandra configuration + * @param serializationFig The serialization configuration + */ + @Inject + public UniqueValueSerializationStrategyV1Impl( final Keyspace keyspace, final CassandraFig cassandraFig, + final SerializationFig serializationFig ) { + super( keyspace, cassandraFig, serializationFig ); + } + + + @Override + public Collection<MultiTennantColumnFamilyDefinition> getColumnFamilies() { + + final MultiTennantColumnFamilyDefinition uniqueLookupCF = + new MultiTennantColumnFamilyDefinition( CF_UNIQUE_VALUES, BytesType.class.getSimpleName(), + ColumnTypes.DYNAMIC_COMPOSITE_TYPE, BytesType.class.getSimpleName(), + MultiTennantColumnFamilyDefinition.CacheOption.KEYS ); + + final MultiTennantColumnFamilyDefinition uniqueLogCF = + new MultiTennantColumnFamilyDefinition( CF_ENTITY_UNIQUE_VALUE_LOG, BytesType.class.getSimpleName(), + ColumnTypes.DYNAMIC_COMPOSITE_TYPE, BytesType.class.getSimpleName(), + MultiTennantColumnFamilyDefinition.CacheOption.KEYS ); + + return Arrays.asList( uniqueLookupCF, uniqueLogCF ); + } + + + @Override + protected MultiTennantColumnFamily<ScopedRowKey<CollectionPrefixedKey<Field>>, EntityVersion> getUniqueValuesCF() { + return CF_UNIQUE_VALUES; + } + + + @Override + protected MultiTennantColumnFamily<ScopedRowKey<CollectionPrefixedKey<Id>>, UniqueFieldEntry> + getEntityUniqueLogCF() { + return CF_ENTITY_UNIQUE_VALUE_LOG; + } + + + @Override + protected CollectionPrefixedKey<Field> createUniqueValueKey( final Id applicationId, + final String type, final Field field) { + + + final String collectionName = LegacyScopeUtils.getCollectionScopeNameFromEntityType( type ); + + + final CollectionPrefixedKey<Field> uniquePrefixedKey = + new CollectionPrefixedKey<>( collectionName, applicationId, field ); + + return uniquePrefixedKey; + } + + + @Override + protected Field parseRowKey( final ScopedRowKey<CollectionPrefixedKey<Field>> rowKey ) { + return rowKey.getKey().getSubKey(); + } + + + @Override + protected CollectionPrefixedKey<Id> createEntityUniqueLogKey( final Id applicationId, + final Id uniqueValueId ) { + + + final String collectionName = LegacyScopeUtils.getCollectionScopeNameFromEntityType( uniqueValueId.getType() ); + + + final CollectionPrefixedKey<Id> collectionPrefixedEntityKey = + new CollectionPrefixedKey<>( collectionName, applicationId, uniqueValueId ); + + + + return collectionPrefixedEntityKey; + } + + + @Override + public int getImplementationVersion() { + return CollectionDataVersions.INITIAL.getVersion(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/d145eb4b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyV2Impl.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyV2Impl.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyV2Impl.java new file mode 100644 index 0000000..baeec22 --- /dev/null +++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyV2Impl.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.usergrid.persistence.collection.serialization.impl; + + +import java.util.Arrays; +import java.util.Collection; + +import org.apache.cassandra.db.marshal.BytesType; + +import org.apache.usergrid.persistence.collection.serialization.SerializationFig; +import org.apache.usergrid.persistence.collection.serialization.impl.util.LegacyScopeUtils; +import org.apache.usergrid.persistence.core.astyanax.CassandraFig; +import org.apache.usergrid.persistence.core.astyanax.ColumnTypes; +import org.apache.usergrid.persistence.core.astyanax.IdRowCompositeSerializer; +import org.apache.usergrid.persistence.core.astyanax.MultiTennantColumnFamily; +import org.apache.usergrid.persistence.core.astyanax.MultiTennantColumnFamilyDefinition; +import org.apache.usergrid.persistence.core.astyanax.ScopedRowKey; +import org.apache.usergrid.persistence.core.astyanax.ScopedRowKeySerializer; +import org.apache.usergrid.persistence.model.entity.Id; +import org.apache.usergrid.persistence.model.field.Field; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.netflix.astyanax.Keyspace; + + +/** + * V1 impl with unique value serialization strategy with the collection scope + */ +@Singleton +public class UniqueValueSerializationStrategyV2Impl extends UniqueValueSerializationStrategyImpl<Field, Id> { + + + private static final ScopedRowKeySerializer<Field> ROW_KEY_SER = new ScopedRowKeySerializer<>( UniqueFieldRowKeySerializer.get() ); + + + private static final EntityVersionSerializer ENTITY_VERSION_SER = new EntityVersionSerializer(); + + private static final MultiTennantColumnFamily<ScopedRowKey<Field>, EntityVersion> + CF_UNIQUE_VALUES = new MultiTennantColumnFamily<>( "Unique_Values_V2", ROW_KEY_SER, ENTITY_VERSION_SER ); + + + private static final IdRowCompositeSerializer ID_SER = IdRowCompositeSerializer.get(); + + + private static final ScopedRowKeySerializer<Id> ENTITY_ROW_KEY_SER = + new ScopedRowKeySerializer<>( ID_SER ); + + + private static final MultiTennantColumnFamily<ScopedRowKey<Id>, UniqueFieldEntry> + CF_ENTITY_UNIQUE_VALUE_LOG = + new MultiTennantColumnFamily<>( "Entity_Unique_Values_V2", ENTITY_ROW_KEY_SER, UniqueFieldEntrySerializer.get() ); + + + /** + * Construct serialization strategy for keyspace. + * + * @param keyspace Keyspace in which to store Unique Values. + * @param cassandraFig The cassandra configuration + * @param serializationFig The serialization configuration + */ + @Inject + public UniqueValueSerializationStrategyV2Impl( final Keyspace keyspace, final CassandraFig cassandraFig, + final SerializationFig serializationFig ) { + super( keyspace, cassandraFig, serializationFig ); + } + + + @Override + public Collection<MultiTennantColumnFamilyDefinition> getColumnFamilies() { + + final MultiTennantColumnFamilyDefinition uniqueLookupCF = + new MultiTennantColumnFamilyDefinition( CF_UNIQUE_VALUES, BytesType.class.getSimpleName(), + ColumnTypes.DYNAMIC_COMPOSITE_TYPE, BytesType.class.getSimpleName(), + MultiTennantColumnFamilyDefinition.CacheOption.KEYS ); + + final MultiTennantColumnFamilyDefinition uniqueLogCF = + new MultiTennantColumnFamilyDefinition( CF_ENTITY_UNIQUE_VALUE_LOG, BytesType.class.getSimpleName(), + ColumnTypes.DYNAMIC_COMPOSITE_TYPE, BytesType.class.getSimpleName(), + MultiTennantColumnFamilyDefinition.CacheOption.KEYS ); + + return Arrays.asList( uniqueLookupCF, uniqueLogCF ); + } + + + @Override + protected MultiTennantColumnFamily<ScopedRowKey<Field>, EntityVersion> getUniqueValuesCF() { + return CF_UNIQUE_VALUES; + } + + + @Override + protected MultiTennantColumnFamily<ScopedRowKey<Id>, UniqueFieldEntry> + getEntityUniqueLogCF() { + return CF_ENTITY_UNIQUE_VALUE_LOG; + } + + + @Override + protected Field createUniqueValueKey( final Id applicationId, final String type, final Field field) { + return field; + } + + + @Override + protected Field parseRowKey( final ScopedRowKey<Field> rowKey ) { + return rowKey.getKey(); + } + + + @Override + protected Id createEntityUniqueLogKey( final Id applicationId, final Id uniqueValueId ) { + return uniqueValueId; + } + + + @Override + public int getImplementationVersion() { + return CollectionDataVersions.LOG_REMOVAL.getVersion(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/d145eb4b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/UniqueValueSerializationStrategyImplTest.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/UniqueValueSerializationStrategyImplTest.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/UniqueValueSerializationStrategyImplTest.java deleted file mode 100644 index e1647b3..0000000 --- a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/UniqueValueSerializationStrategyImplTest.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. 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. For additional information regarding - * copyright in this work, please see the NOTICE file in the top level - * directory of this distribution. - */ -package org.apache.usergrid.persistence.collection.mvcc.stage.write; - - -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.UUID; - -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.apache.usergrid.persistence.collection.guice.TestCollectionModule; -import org.apache.usergrid.persistence.collection.serialization.UniqueValue; -import org.apache.usergrid.persistence.collection.serialization.UniqueValueSerializationStrategy; -import org.apache.usergrid.persistence.collection.serialization.UniqueValueSet; -import org.apache.usergrid.persistence.collection.serialization.impl.UniqueValueImpl; -import org.apache.usergrid.persistence.core.guice.MigrationManagerRule; -import org.apache.usergrid.persistence.core.scope.ApplicationScope; -import org.apache.usergrid.persistence.core.scope.ApplicationScopeImpl; -import org.apache.usergrid.persistence.core.test.ITRunner; -import org.apache.usergrid.persistence.core.test.UseModules; -import org.apache.usergrid.persistence.model.entity.Id; -import org.apache.usergrid.persistence.model.entity.SimpleId; -import org.apache.usergrid.persistence.model.field.Field; -import org.apache.usergrid.persistence.model.field.IntegerField; -import org.apache.usergrid.persistence.model.field.StringField; -import org.apache.usergrid.persistence.model.util.UUIDGenerator; - -import com.google.inject.Inject; -import com.netflix.astyanax.MutationBatch; -import com.netflix.astyanax.connectionpool.exceptions.ConnectionException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - - -@RunWith(ITRunner.class) -@UseModules(TestCollectionModule.class) -public class UniqueValueSerializationStrategyImplTest { - - - @Inject - @Rule - public MigrationManagerRule migrationManagerRule; - - @Inject - UniqueValueSerializationStrategy strategy; - - - @Test - public void testBasicOperation() throws ConnectionException, InterruptedException { - - ApplicationScope scope = - new ApplicationScopeImpl( new SimpleId( "organization" ) ); - - IntegerField field = new IntegerField( "count", 5 ); - Id entityId = new SimpleId( UUIDGenerator.newTimeUUID(), "entity" ); - UUID version = UUIDGenerator.newTimeUUID(); - UniqueValue stored = new UniqueValueImpl( field, entityId, version ); - strategy.write( scope, stored ).execute(); - - UniqueValueSet fields = strategy.load( scope, entityId.getType(), Collections.<Field>singleton( field ) ); - - UniqueValue retrieved = fields.getValue( field.getName() ); - Assert.assertNotNull( retrieved ); - assertEquals( stored, retrieved ); - - Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields( scope, entityId ); - - assertTrue(allFieldsWritten.hasNext()); - - //test this interface. In most cases, we won't know the field name, so we want them all - UniqueValue allFieldsValue = allFieldsWritten.next(); - Assert.assertNotNull( allFieldsValue ); - - assertEquals( field, allFieldsValue.getField() ); - assertEquals(version, allFieldsValue.getEntityVersion()); - - assertFalse(allFieldsWritten.hasNext()); - - } - - - @Test - public void testWriteWithTTL() throws InterruptedException, ConnectionException { - - - ApplicationScope scope = - new ApplicationScopeImpl( new SimpleId( "organization" ) ); - - // write object that lives 2 seconds - IntegerField field = new IntegerField( "count", 5 ); - Id entityId = new SimpleId( UUIDGenerator.newTimeUUID(), "entity" ); - UUID version = UUIDGenerator.newTimeUUID(); - UniqueValue stored = new UniqueValueImpl( field, entityId, version ); - strategy.write( scope, stored, 2 ).execute(); - - Thread.sleep( 1000 ); - - // waited one sec, should be still here - UniqueValueSet fields = strategy.load( scope, entityId.getType(), Collections.<Field>singleton( field ) ); - - UniqueValue retrieved = fields.getValue( field.getName() ); - - Assert.assertNotNull( retrieved ); - assertEquals( stored, retrieved ); - - Thread.sleep( 1500 ); - - // wait another second, should be gone now - fields = strategy.load( scope, entityId.getType(), Collections.<Field>singleton( field ) ); - - UniqueValue nullExpected = fields.getValue( field.getName() ); - Assert.assertNull( nullExpected ); - - - //we still want to retain the log entry, even if we don't retain the unique value. Deleting something - //that doesn't exist is a tombstone, but so is the timeout. - Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields( scope, entityId ); - - assertTrue( allFieldsWritten.hasNext() ); - - //test this interface. In most cases, we won't know the field name, so we want them all - UniqueValue writtenFieldEntry = allFieldsWritten.next(); - Assert.assertNotNull( writtenFieldEntry ); - - assertEquals( field, writtenFieldEntry.getField() ); - assertEquals( version, writtenFieldEntry.getEntityVersion() ); - - assertFalse(allFieldsWritten.hasNext()); - - - - } - - - @Test - public void testDelete() throws ConnectionException { - - - ApplicationScope scope = - new ApplicationScopeImpl( new SimpleId( "organization" ) ); - - IntegerField field = new IntegerField( "count", 5 ); - Id entityId = new SimpleId( UUIDGenerator.newTimeUUID(), "entity" ); - UUID version = UUIDGenerator.newTimeUUID(); - UniqueValue stored = new UniqueValueImpl( field, entityId, version ); - strategy.write( scope, stored ).execute(); - - strategy.delete( scope, stored ).execute(); - - UniqueValueSet fields = strategy.load( scope, entityId.getType(), Collections.<Field>singleton( field ) ); - - UniqueValue nullExpected = fields.getValue( field.getName() ); - - - Assert.assertNull( nullExpected ); - - - Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields( scope, entityId ); - - assertFalse("No entries left", allFieldsWritten.hasNext() ); - } - - - @Test - public void testCapitalizationFixes() throws ConnectionException { - - ApplicationScope scope = - new ApplicationScopeImpl( new SimpleId( "organization" ) ); - - StringField field = new StringField( "count", "MiXeD CaSe" ); - Id entityId = new SimpleId( UUIDGenerator.newTimeUUID(), "entity" ); - UUID version = UUIDGenerator.newTimeUUID(); - UniqueValue stored = new UniqueValueImpl( field, entityId, version ); - strategy.write( scope, stored ).execute(); - - - UniqueValueSet fields = strategy.load( scope, entityId.getType(), Collections.<Field>singleton( field ) ); - - UniqueValue value = fields.getValue( field.getName() ); - - - assertEquals( field.getName(), value.getField().getName() ); - - assertEquals( entityId, value.getEntityId() ); - - //now test will all upper and all lower, we should get it all the same - fields = strategy.load( scope, entityId.getType(), - Collections.<Field>singleton( new StringField( field.getName(), "MIXED CASE" ) ) ); - - value = fields.getValue( field.getName() ); - - - assertEquals( field.getName(), value.getField().getName() ); - - assertEquals( entityId, value.getEntityId() ); - - fields = strategy.load( scope, entityId.getType(), - Collections.<Field>singleton( new StringField( field.getName(), "mixed case" ) ) ); - - value = fields.getValue( field.getName() ); - - - assertEquals( field.getName(), value.getField().getName() ); - - assertEquals( entityId, value.getEntityId() ); - - - Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields( scope, entityId ); - - assertTrue( allFieldsWritten.hasNext() ); - - //test this interface. In most cases, we won't know the field name, so we want them all - UniqueValue writtenFieldEntry = allFieldsWritten.next(); - Assert.assertNotNull( writtenFieldEntry ); - - assertEquals( field.getName(), writtenFieldEntry.getField().getName() ); - assertEquals( field.getValue().toLowerCase(), writtenFieldEntry.getField().getValue() ); - assertEquals( version, writtenFieldEntry.getEntityVersion() ); - - assertFalse(allFieldsWritten.hasNext()); - } - - - - @Test - public void twoFieldsPerVersion() throws ConnectionException, InterruptedException { - - - ApplicationScope scope = - new ApplicationScopeImpl( new SimpleId( "organization" ) ); - - - Id entityId = new SimpleId( UUIDGenerator.newTimeUUID(), "entity" ); - final UUID version1 = UUIDGenerator.newTimeUUID(); - - - //write V1 of everything - IntegerField version1Field1 = new IntegerField( "count", 1 ); - StringField version1Field2 = new StringField("field", "v1value"); - - - UniqueValue version1Field1Value = new UniqueValueImpl( version1Field1, entityId, version1 ); - UniqueValue version1Field2Value = new UniqueValueImpl( version1Field2, entityId, version1 ); - - final MutationBatch batch = strategy.write( scope, version1Field1Value ); - batch.mergeShallow( strategy.write( scope, version1Field2Value ) ); - - - //write V2 of everything - final UUID version2 = UUIDGenerator.newTimeUUID(); - - IntegerField version2Field1 = new IntegerField( "count", 2 ); - StringField version2Field2 = new StringField( "field", "v2value" ); - - - UniqueValue version2Field1Value = new UniqueValueImpl( version2Field1, entityId, version2 ); - UniqueValue version2Field2Value = new UniqueValueImpl( version2Field2, entityId, version2 ); - - batch.mergeShallow( strategy.write( scope, version2Field1Value ) ); - batch.mergeShallow( strategy.write( scope, version2Field2Value ) ); - - batch.execute(); - - - UniqueValueSet fields = strategy.load( scope, entityId.getType(), Arrays.<Field>asList( version1Field1, version1Field2 ) ); - - UniqueValue retrieved = fields.getValue( version1Field1.getName() ); - - assertEquals( version1Field1Value, retrieved ); - - - retrieved = fields.getValue( version1Field2.getName() ); - assertEquals( version1Field2Value, retrieved ); - - - Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields( scope, entityId ); - - assertTrue(allFieldsWritten.hasNext()); - - //test this interface. In most cases, we won't know the field name, so we want them all - UniqueValue allFieldsValue = allFieldsWritten.next(); - - //version 2 fields should come first, ordered by field name - assertEquals( version2Field1, allFieldsValue.getField() ); - assertEquals( version2, allFieldsValue.getEntityVersion() ); - - allFieldsValue = allFieldsWritten.next(); - - assertEquals( version2Field2, allFieldsValue.getField() ); - assertEquals( version2, allFieldsValue.getEntityVersion() ); - - - //version 1 should come next ordered by field name - allFieldsValue = allFieldsWritten.next(); - - assertEquals( version1Field1, allFieldsValue.getField() ); - assertEquals( version1, allFieldsValue.getEntityVersion() ); - - allFieldsValue = allFieldsWritten.next(); - - assertEquals( version1Field2, allFieldsValue.getField() ); - assertEquals( version1, allFieldsValue.getEntityVersion() ); - - assertFalse(allFieldsWritten.hasNext()); - - } - -} http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/d145eb4b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyImplTest.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyImplTest.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyImplTest.java new file mode 100644 index 0000000..2fae482 --- /dev/null +++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyImplTest.java @@ -0,0 +1,344 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package org.apache.usergrid.persistence.collection.serialization.impl; + + +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.UUID; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.apache.usergrid.persistence.collection.guice.TestCollectionModule; +import org.apache.usergrid.persistence.collection.serialization.UniqueValue; +import org.apache.usergrid.persistence.collection.serialization.UniqueValueSerializationStrategy; +import org.apache.usergrid.persistence.collection.serialization.UniqueValueSet; +import org.apache.usergrid.persistence.collection.serialization.impl.UniqueValueImpl; +import org.apache.usergrid.persistence.core.guice.MigrationManagerRule; +import org.apache.usergrid.persistence.core.scope.ApplicationScope; +import org.apache.usergrid.persistence.core.scope.ApplicationScopeImpl; +import org.apache.usergrid.persistence.core.test.ITRunner; +import org.apache.usergrid.persistence.core.test.UseModules; +import org.apache.usergrid.persistence.model.entity.Id; +import org.apache.usergrid.persistence.model.entity.SimpleId; +import org.apache.usergrid.persistence.model.field.Field; +import org.apache.usergrid.persistence.model.field.IntegerField; +import org.apache.usergrid.persistence.model.field.StringField; +import org.apache.usergrid.persistence.model.util.UUIDGenerator; + +import com.google.inject.Inject; +import com.netflix.astyanax.MutationBatch; +import com.netflix.astyanax.connectionpool.exceptions.ConnectionException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + + +@RunWith(ITRunner.class) +@UseModules(TestCollectionModule.class) +public abstract class UniqueValueSerializationStrategyImplTest { + + + @Inject + @Rule + public MigrationManagerRule migrationManagerRule; + + + private UniqueValueSerializationStrategy strategy; + + + @Before + public void wireUniqueSerializationStrategy(){ + strategy = getUniqueSerializationStrategy(); + } + + + /** + * Get the unique value serialization + * @return + */ + protected abstract UniqueValueSerializationStrategy getUniqueSerializationStrategy(); + + + @Test + public void testBasicOperation() throws ConnectionException, InterruptedException { + + ApplicationScope scope = + new ApplicationScopeImpl( new SimpleId( "organization" ) ); + + IntegerField field = new IntegerField( "count", 5 ); + Id entityId = new SimpleId( UUIDGenerator.newTimeUUID(), "entity" ); + UUID version = UUIDGenerator.newTimeUUID(); + UniqueValue stored = new UniqueValueImpl( field, entityId, version ); + strategy.write( scope, stored ).execute(); + + UniqueValueSet fields = strategy.load( scope, entityId.getType(), Collections.<Field>singleton( field ) ); + + UniqueValue retrieved = fields.getValue( field.getName() ); + Assert.assertNotNull( retrieved ); + assertEquals( stored, retrieved ); + + Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields( scope, entityId ); + + assertTrue(allFieldsWritten.hasNext()); + + //test this interface. In most cases, we won't know the field name, so we want them all + UniqueValue allFieldsValue = allFieldsWritten.next(); + Assert.assertNotNull( allFieldsValue ); + + assertEquals( field, allFieldsValue.getField() ); + assertEquals(version, allFieldsValue.getEntityVersion()); + + assertFalse(allFieldsWritten.hasNext()); + + } + + + @Test + public void testWriteWithTTL() throws InterruptedException, ConnectionException { + + + ApplicationScope scope = + new ApplicationScopeImpl( new SimpleId( "organization" ) ); + + // write object that lives 2 seconds + IntegerField field = new IntegerField( "count", 5 ); + Id entityId = new SimpleId( UUIDGenerator.newTimeUUID(), "entity" ); + UUID version = UUIDGenerator.newTimeUUID(); + UniqueValue stored = new UniqueValueImpl( field, entityId, version ); + strategy.write( scope, stored, 2 ).execute(); + + Thread.sleep( 1000 ); + + // waited one sec, should be still here + UniqueValueSet fields = strategy.load( scope, entityId.getType(), Collections.<Field>singleton( field ) ); + + UniqueValue retrieved = fields.getValue( field.getName() ); + + Assert.assertNotNull( retrieved ); + assertEquals( stored, retrieved ); + + Thread.sleep( 1500 ); + + // wait another second, should be gone now + fields = strategy.load( scope, entityId.getType(), Collections.<Field>singleton( field ) ); + + UniqueValue nullExpected = fields.getValue( field.getName() ); + Assert.assertNull( nullExpected ); + + + //we still want to retain the log entry, even if we don't retain the unique value. Deleting something + //that doesn't exist is a tombstone, but so is the timeout. + Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields( scope, entityId ); + + assertTrue( allFieldsWritten.hasNext() ); + + //test this interface. In most cases, we won't know the field name, so we want them all + UniqueValue writtenFieldEntry = allFieldsWritten.next(); + Assert.assertNotNull( writtenFieldEntry ); + + assertEquals( field, writtenFieldEntry.getField() ); + assertEquals( version, writtenFieldEntry.getEntityVersion() ); + + assertFalse(allFieldsWritten.hasNext()); + + + + } + + + @Test + public void testDelete() throws ConnectionException { + + + ApplicationScope scope = + new ApplicationScopeImpl( new SimpleId( "organization" ) ); + + IntegerField field = new IntegerField( "count", 5 ); + Id entityId = new SimpleId( UUIDGenerator.newTimeUUID(), "entity" ); + UUID version = UUIDGenerator.newTimeUUID(); + UniqueValue stored = new UniqueValueImpl( field, entityId, version ); + strategy.write( scope, stored ).execute(); + + strategy.delete( scope, stored ).execute(); + + UniqueValueSet fields = strategy.load( scope, entityId.getType(), Collections.<Field>singleton( field ) ); + + UniqueValue nullExpected = fields.getValue( field.getName() ); + + + Assert.assertNull( nullExpected ); + + + Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields( scope, entityId ); + + assertFalse("No entries left", allFieldsWritten.hasNext() ); + } + + + @Test + public void testCapitalizationFixes() throws ConnectionException { + + ApplicationScope scope = + new ApplicationScopeImpl( new SimpleId( "organization" ) ); + + StringField field = new StringField( "count", "MiXeD CaSe" ); + Id entityId = new SimpleId( UUIDGenerator.newTimeUUID(), "entity" ); + UUID version = UUIDGenerator.newTimeUUID(); + UniqueValue stored = new UniqueValueImpl( field, entityId, version ); + strategy.write( scope, stored ).execute(); + + + UniqueValueSet fields = strategy.load( scope, entityId.getType(), Collections.<Field>singleton( field ) ); + + UniqueValue value = fields.getValue( field.getName() ); + + + assertEquals( field.getName(), value.getField().getName() ); + + assertEquals( entityId, value.getEntityId() ); + + //now test will all upper and all lower, we should get it all the same + fields = strategy.load( scope, entityId.getType(), + Collections.<Field>singleton( new StringField( field.getName(), "MIXED CASE" ) ) ); + + value = fields.getValue( field.getName() ); + + + assertEquals( field.getName(), value.getField().getName() ); + + assertEquals( entityId, value.getEntityId() ); + + fields = strategy.load( scope, entityId.getType(), + Collections.<Field>singleton( new StringField( field.getName(), "mixed case" ) ) ); + + value = fields.getValue( field.getName() ); + + + assertEquals( field.getName(), value.getField().getName() ); + + assertEquals( entityId, value.getEntityId() ); + + + Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields( scope, entityId ); + + assertTrue( allFieldsWritten.hasNext() ); + + //test this interface. In most cases, we won't know the field name, so we want them all + UniqueValue writtenFieldEntry = allFieldsWritten.next(); + Assert.assertNotNull( writtenFieldEntry ); + + assertEquals( field.getName(), writtenFieldEntry.getField().getName() ); + assertEquals( field.getValue().toLowerCase(), writtenFieldEntry.getField().getValue() ); + assertEquals( version, writtenFieldEntry.getEntityVersion() ); + + assertFalse(allFieldsWritten.hasNext()); + } + + + + @Test + public void twoFieldsPerVersion() throws ConnectionException, InterruptedException { + + + ApplicationScope scope = + new ApplicationScopeImpl( new SimpleId( "organization" ) ); + + + Id entityId = new SimpleId( UUIDGenerator.newTimeUUID(), "entity" ); + final UUID version1 = UUIDGenerator.newTimeUUID(); + + + //write V1 of everything + IntegerField version1Field1 = new IntegerField( "count", 1 ); + StringField version1Field2 = new StringField("field", "v1value"); + + + UniqueValue version1Field1Value = new UniqueValueImpl( version1Field1, entityId, version1 ); + UniqueValue version1Field2Value = new UniqueValueImpl( version1Field2, entityId, version1 ); + + final MutationBatch batch = strategy.write( scope, version1Field1Value ); + batch.mergeShallow( strategy.write( scope, version1Field2Value ) ); + + + //write V2 of everything + final UUID version2 = UUIDGenerator.newTimeUUID(); + + IntegerField version2Field1 = new IntegerField( "count", 2 ); + StringField version2Field2 = new StringField( "field", "v2value" ); + + + UniqueValue version2Field1Value = new UniqueValueImpl( version2Field1, entityId, version2 ); + UniqueValue version2Field2Value = new UniqueValueImpl( version2Field2, entityId, version2 ); + + batch.mergeShallow( strategy.write( scope, version2Field1Value ) ); + batch.mergeShallow( strategy.write( scope, version2Field2Value ) ); + + batch.execute(); + + + UniqueValueSet fields = strategy.load( scope, entityId.getType(), Arrays.<Field>asList( version1Field1, version1Field2 ) ); + + UniqueValue retrieved = fields.getValue( version1Field1.getName() ); + + assertEquals( version1Field1Value, retrieved ); + + + retrieved = fields.getValue( version1Field2.getName() ); + assertEquals( version1Field2Value, retrieved ); + + + Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields( scope, entityId ); + + assertTrue(allFieldsWritten.hasNext()); + + //test this interface. In most cases, we won't know the field name, so we want them all + UniqueValue allFieldsValue = allFieldsWritten.next(); + + //version 2 fields should come first, ordered by field name + assertEquals( version2Field1, allFieldsValue.getField() ); + assertEquals( version2, allFieldsValue.getEntityVersion() ); + + allFieldsValue = allFieldsWritten.next(); + + assertEquals( version2Field2, allFieldsValue.getField() ); + assertEquals( version2, allFieldsValue.getEntityVersion() ); + + + //version 1 should come next ordered by field name + allFieldsValue = allFieldsWritten.next(); + + assertEquals( version1Field1, allFieldsValue.getField() ); + assertEquals( version1, allFieldsValue.getEntityVersion() ); + + allFieldsValue = allFieldsWritten.next(); + + assertEquals( version1Field2, allFieldsValue.getField() ); + assertEquals( version1, allFieldsValue.getEntityVersion() ); + + assertFalse(allFieldsWritten.hasNext()); + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/d145eb4b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyProxyImplTest.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyProxyImplTest.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyProxyImplTest.java new file mode 100644 index 0000000..a74ddc2 --- /dev/null +++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/impl/UniqueValueSerializationStrategyProxyImplTest.java @@ -0,0 +1,100 @@ +/* + * 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.usergrid.persistence.collection.serialization.impl; + + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.apache.usergrid.persistence.collection.guice.TestCollectionModule; +import org.apache.usergrid.persistence.collection.serialization.MvccLogEntrySerializationStrategy; +import org.apache.usergrid.persistence.collection.serialization.UniqueValueSerializationStrategy; +import org.apache.usergrid.persistence.collection.serialization.impl.migration.CollectionMigrationPlugin; +import org.apache.usergrid.persistence.core.migration.data.MigrationInfoSerialization; +import org.apache.usergrid.persistence.core.test.ITRunner; +import org.apache.usergrid.persistence.core.test.UseModules; + +import com.google.inject.Inject; +import com.netflix.astyanax.connectionpool.exceptions.ConnectionException; + +import net.jcip.annotations.NotThreadSafe; + +import static org.junit.Assert.assertEquals; + + +@RunWith( ITRunner.class ) +@UseModules( TestCollectionModule.class ) +@NotThreadSafe +public class UniqueValueSerializationStrategyProxyImplTest extends UniqueValueSerializationStrategyImplTest { + + @Inject + private UniqueValueSerializationStrategyV1Impl strategy; + + + @Inject + private UniqueValueSerializationStrategyV1Impl v1Impl; + + + + /** + * Get the unique value serialization + */ + protected UniqueValueSerializationStrategy getUniqueSerializationStrategy() { + return strategy; + } + + + + + + + @Inject + protected MigrationInfoSerialization migrationInfoSerialization; + + private int existingVersion; + + + + + + + /** + * We need to run our migration to ensure that we are on the current version, and everything still functions + * correctly + */ + @Before + public void setMigrationVersion() { + existingVersion = migrationInfoSerialization.getVersion( CollectionMigrationPlugin.PLUGIN_NAME); + + //set our migration version to be v1 + migrationInfoSerialization.setVersion( CollectionMigrationPlugin.PLUGIN_NAME, v1Impl.getImplementationVersion() ); + } + + + + + @After + public void reSetMigrationVersion() { + migrationInfoSerialization.setVersion( CollectionMigrationPlugin.PLUGIN_NAME, existingVersion ); + } + +}
