You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by to...@apache.org on 2015/03/31 19:35:32 UTC
[2/2] incubator-usergrid git commit: Implemented new row key for
unique values.
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/USERGRID-509
Commit: d145eb4b8e97c2eb4cb02fa568f357e5f8e7c5e2
Parents: 6e3fab6
Author: Todd Nine <tn...@apigee.com>
Authored: Tue Mar 31 11:35:31 2015 -0600
Committer: Todd Nine <tn...@apigee.com>
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 );
+ }
+
+}