You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2016/06/29 12:45:25 UTC

[15/38] usergrid git commit: Add new tool for scanning unique values. Include option to skip read repair in the methods that load entities from the unique index.

Add new tool for scanning unique values.  Include option to skip read repair in the methods that load entities from the unique index.


Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/06f77d7b
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/06f77d7b
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/06f77d7b

Branch: refs/heads/usergrid-1268-akka-211
Commit: 06f77d7b385efdcb3655035e895d89f99710a70a
Parents: 9efa3b4
Author: Michael Russo <mr...@apigee.com>
Authored: Tue Jun 21 14:29:50 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Tue Jun 21 14:29:50 2016 -0700

----------------------------------------------------------------------
 .../corepersistence/CpEntityManager.java        |   9 +-
 .../usergrid/persistence/EntityManager.java     |   2 +-
 .../collection/EntityCollectionManager.java     |   3 +-
 .../impl/EntityCollectionManagerImpl.java       |   7 +-
 .../UniqueValueSerializationStrategyImpl.java   |  15 +-
 .../collection/EntityCollectionManagerIT.java   |  63 +++--
 .../services/AbstractCollectionService.java     |   8 +-
 .../services/AbstractConnectionsService.java    |   6 +-
 .../usergrid/tools/UniqueValueScanner.java      | 245 +++++++++++++++++++
 9 files changed, 314 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/06f77d7b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
index 82c4c87..ab62b36 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
@@ -853,10 +853,9 @@ public class CpEntityManager implements EntityManager {
     }
 
     @Override
-    public Entity getUniqueEntityFromAlias( String collectionType, String aliasType ){
-        String collName = Schema.defaultCollectionName( collectionType );
-
+    public Entity getUniqueEntityFromAlias(String collectionType, String aliasType, boolean useReadRepair){
 
+        String collName = Schema.defaultCollectionName( collectionType );
         String propertyName = Schema.getDefaultSchema().aliasProperty( collName );
 
         Timer.Context repairedEntityGet = entGetRepairedEntityTimer.time();
@@ -867,7 +866,7 @@ public class CpEntityManager implements EntityManager {
         StringField uniqueLookupRepairField =  new StringField( propertyName, aliasType.toString());
 
         Observable<FieldSet> fieldSetObservable = ecm.getEntitiesFromFields(
-            Inflector.getInstance().singularize( collectionType ), Arrays.<Field>asList( uniqueLookupRepairField ) );
+            Inflector.getInstance().singularize( collectionType ), Arrays.<Field>asList( uniqueLookupRepairField ), useReadRepair);
 
         if(fieldSetObservable == null){
 
@@ -901,7 +900,7 @@ public class CpEntityManager implements EntityManager {
         StringField uniqueLookupRepairField =  new StringField( propertyName, aliasType);
 
         Observable<FieldSet> fieldSetObservable = ecm.getEntitiesFromFields(
-            Inflector.getInstance().singularize( collectionType ), Collections.singletonList(uniqueLookupRepairField));
+            Inflector.getInstance().singularize( collectionType ), Collections.singletonList(uniqueLookupRepairField), true);
 
         if(fieldSetObservable == null){
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/06f77d7b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManager.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManager.java b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManager.java
index ef96f10..53a7a89 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManager.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManager.java
@@ -709,7 +709,7 @@ public interface EntityManager {
     public void flushManagerCaches();
 
 
-    public Entity getUniqueEntityFromAlias( String aliasType, String aliasValue );
+    public Entity getUniqueEntityFromAlias(String aliasType, String aliasValue, boolean useReadRepair);
 
     public UUID getUniqueIdFromAlias( String aliasType, String aliasValue );
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/06f77d7b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java
index 22fbb5f..ed43775 100644
--- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java
+++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java
@@ -76,9 +76,10 @@ public interface EntityCollectionManager {
      * Get a fieldset of all fields from the entities
      * @param entityType The type of entity.  From the "type" field in the id.
      * @param fields The collection of fields to search
+     * @param useReadRepair
      * @return
      */
-    Observable<FieldSet> getEntitiesFromFields( String entityType, Collection<Field> fields );
+    Observable<FieldSet> getEntitiesFromFields(String entityType, Collection<Field> fields, boolean useReadRepair);
 
     /**
      * Gets the Id for a field

http://git-wip-us.apache.org/repos/asf/usergrid/blob/06f77d7b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java
index 77e452f..1ccc18f 100644
--- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java
+++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java
@@ -65,7 +65,6 @@ import org.apache.usergrid.persistence.core.util.ValidationUtils;
 import org.apache.usergrid.persistence.model.entity.Entity;
 import org.apache.usergrid.persistence.model.entity.Id;
 import org.apache.usergrid.persistence.model.field.Field;
-import org.apache.usergrid.persistence.model.util.EntityUtils;
 import org.apache.usergrid.persistence.model.util.UUIDGenerator;
 
 import com.codahale.metrics.Timer;
@@ -82,7 +81,6 @@ import com.netflix.astyanax.serializers.StringSerializer;
 
 import rx.Observable;
 import rx.Subscriber;
-import rx.functions.Action0;
 
 
 /**
@@ -327,7 +325,7 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager {
      * Retrieves all entities that correspond to each field given in the Collection.
      */
     @Override
-    public Observable<FieldSet> getEntitiesFromFields( final String type, final Collection<Field> fields ) {
+    public Observable<FieldSet> getEntitiesFromFields(final String type, final Collection<Field> fields, boolean useReadRepair) {
         final Observable<FieldSet> fieldSetObservable = Observable.just( fields ).map( fields1 -> {
             try {
 
@@ -408,7 +406,7 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager {
                     response.addEntity( expectedUnique.getField(), entity );
                 }
 
-                if ( deleteBatch.getRowCount() > 0 ) {
+                if ( useReadRepair && deleteBatch.getRowCount() > 0 ) {
 
                     deleteBatch.execute();
 
@@ -436,7 +434,6 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager {
                 }
 
 
-
                 return response;
             }
             catch ( ConnectionException e ) {

http://git-wip-us.apache.org/repos/asf/usergrid/blob/06f77d7b/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 622ebef..f7d5199 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
@@ -64,7 +64,7 @@ import com.netflix.astyanax.util.RangeBuilder;
 public abstract class UniqueValueSerializationStrategyImpl<FieldKey, EntityKey>
     implements UniqueValueSerializationStrategy {
 
-    private static final Logger log = LoggerFactory.getLogger( UniqueValueSerializationStrategyImpl.class );
+    private static final Logger logger = LoggerFactory.getLogger( UniqueValueSerializationStrategyImpl.class );
 
 
     private final MultiTenantColumnFamily<ScopedRowKey<FieldKey>, EntityVersion>
@@ -159,7 +159,7 @@ public abstract class UniqueValueSerializationStrategyImpl<FieldKey, EntityKey>
 
 
             //we purposefully leave out TTL.  Worst case we issue deletes against tombstoned columns
-            //best case, we clean up an invalid secondary index entry when the log is used
+            //best case, we clean up an invalid secondary index entry when the logger is used
             @Override
             public void doLog( final ColumnListMutation<UniqueFieldEntry> colMutation ) {
                 colMutation.putColumn( uniqueFieldEntry, COL_VALUE );
@@ -225,8 +225,8 @@ public abstract class UniqueValueSerializationStrategyImpl<FieldKey, EntityKey>
             ScopedRowKey.fromKey( applicationId, entityKey ) ) );
 
 
-        if ( log.isTraceEnabled() ) {
-            log.trace( "Writing unique value version={} name={} value={} ",
+        if ( logger.isTraceEnabled() ) {
+            logger.trace( "Writing unique value version={} name={} value={} ",
                     uniqueValue.getEntityVersion(), uniqueValue.getField().getName(),
                     uniqueValue.getField().getValue()
                 );
@@ -296,6 +296,13 @@ public abstract class UniqueValueSerializationStrategyImpl<FieldKey, EntityKey>
             final UniqueValueImpl uniqueValue =
                 new UniqueValueImpl( field, entityVersion.getEntityId(), entityVersion.getEntityVersion() );
 
+            if(logger.isTraceEnabled()){
+                logger.trace("Putting unique value [{}={}] into result set with entity id [{}] and entity version [{}]",
+                    field.getName(), field.getValue().toString(),
+                    entityVersion.getEntityId(),
+                    entityVersion.getEntityVersion());
+            }
+
             uniqueValueSet.addValue( uniqueValue );
         }
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/06f77d7b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/EntityCollectionManagerIT.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/EntityCollectionManagerIT.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/EntityCollectionManagerIT.java
index 115be99..10c7eb7 100644
--- a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/EntityCollectionManagerIT.java
+++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/EntityCollectionManagerIT.java
@@ -20,7 +20,6 @@ package org.apache.usergrid.persistence.collection;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 
@@ -118,27 +117,49 @@ public class EntityCollectionManagerIT {
 
         EntityCollectionManager manager = factory.createCollectionManager( context );
 
-        {
-            Entity newEntity = new Entity( new SimpleId( "test" ) );
-            newEntity.setField( new IntegerField( "count", 5, true ) );
+        Entity entity = new Entity( new SimpleId( "test" ) );
+        entity.setField( new IntegerField( "count", 5, true ) );
+
+        Observable<Entity> firstWrite = manager.write( entity );
+
+        Entity newEntity = null;
+        Entity firstReturned = null;
+
+        for(int i=0; i<500; i++){
 
-            Observable<Entity> observable = manager.write( newEntity );
-            Entity returned = observable.toBlocking().lastOrDefault( null );
-        }
 
-        {
-            try {
-                Entity newEntity = new Entity( new SimpleId( "test" ) );
-                newEntity.setField( new IntegerField( "count", 5, true ) );
-
-                manager.write( newEntity ).toBlocking().last();
-                fail( "Write should have thrown an exception" );
-            }
-            catch ( Exception ex ) {
-                WriteUniqueVerifyException e = ( WriteUniqueVerifyException ) ex;
-                assertEquals( 1, e.getVioliations().size() );
-            }
+            firstReturned = firstWrite.toBlocking().lastOrDefault( null );
+
         }
+
+//        try {
+//            //newEntity = new Entity( new SimpleId( "test" ) );
+//            //newEntity.setField( new IntegerField( "count", 5, true ) );
+//
+//            Observable<Entity> secondWrite = manager.write( entity );
+//            secondReturned = secondWrite.toBlocking().lastOrDefault( null );
+//
+//            //fail( "Write should have thrown an exception" );
+//        }
+//        catch ( Exception ex ) {
+//            WriteUniqueVerifyException e = ( WriteUniqueVerifyException ) ex;
+//            assertEquals( 1, e.getVioliations().size() );
+//        }
+
+        // try fetching the original one again
+
+        assertEquals(entity.getId().getUuid(), firstReturned.getId().getUuid());
+        assertEquals(entity.getVersion(), firstReturned.getVersion());
+
+
+        //assertEquals(newEntity.getId().getUuid(), secondReturned.getId().getUuid());
+        //assertEquals(newEntity.getVersion(), secondReturned.getVersion());
+
+
+
+
+
+
     }
 
 
@@ -737,7 +758,7 @@ public class EntityCollectionManagerIT {
         assertNotNull( "Version was assigned", createReturned.getVersion() );
 
         FieldSet fieldResults =
-            manager.getEntitiesFromFields( newEntity.getId().getType(), Arrays.<Field>asList( expectedInteger ) )
+            manager.getEntitiesFromFields( newEntity.getId().getType(), Arrays.<Field>asList( expectedInteger ), false)
                    .toBlocking().last();
 
         assertEquals( 1, fieldResults.size() );
@@ -754,7 +775,7 @@ public class EntityCollectionManagerIT {
 
         //try to load via the unique field, should have triggered repair
         final FieldSet results =
-            manager.getEntitiesFromFields( newEntity.getId().getType(), Arrays.<Field>asList( expectedInteger ) )
+            manager.getEntitiesFromFields( newEntity.getId().getType(), Arrays.<Field>asList( expectedInteger ), false)
                    .toBlocking().last();
 
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/06f77d7b/stack/services/src/main/java/org/apache/usergrid/services/AbstractCollectionService.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/services/AbstractCollectionService.java b/stack/services/src/main/java/org/apache/usergrid/services/AbstractCollectionService.java
index c5473cf..7b9e230 100644
--- a/stack/services/src/main/java/org/apache/usergrid/services/AbstractCollectionService.java
+++ b/stack/services/src/main/java/org/apache/usergrid/services/AbstractCollectionService.java
@@ -85,7 +85,7 @@ public class AbstractCollectionService extends AbstractService {
             nameProperty = "name";
         }
 
-        Entity entity = em.getUniqueEntityFromAlias( getEntityType(), name );
+        Entity entity = em.getUniqueEntityFromAlias( getEntityType(), name, true);
         if ( entity != null ) {
             entity = importEntity( request, entity );
         }
@@ -282,7 +282,7 @@ public class AbstractCollectionService extends AbstractService {
         }
 
        // EntityRef ref = em.getAlias( getEntityType(), name );
-        Entity entity = em.getUniqueEntityFromAlias( getEntityType(), name );
+        Entity entity = em.getUniqueEntityFromAlias( getEntityType(), name, true);
         if ( entity == null ) {
             // null entity ref means we tried to put a non-existing entity
             // before we create a new entity for it, we should check for permission
@@ -477,7 +477,7 @@ public class AbstractCollectionService extends AbstractService {
             return super.postItemByName( context, name );
         }
 
-        Entity entity = em.getUniqueEntityFromAlias( getEntityType(), name );
+        Entity entity = em.getUniqueEntityFromAlias( getEntityType(), name, true);
         if ( entity == null ) {
             throw new ServiceResourceNotFoundException( context );
         }
@@ -531,7 +531,7 @@ public class AbstractCollectionService extends AbstractService {
             return getItemByName( context, name );
         }
 
-        Entity entity = em.getUniqueEntityFromAlias( getEntityType(), name );
+        Entity entity = em.getUniqueEntityFromAlias( getEntityType(), name, true);
         if ( entity == null ) {
             throw new ServiceResourceNotFoundException( context );
         }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/06f77d7b/stack/services/src/main/java/org/apache/usergrid/services/AbstractConnectionsService.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/services/AbstractConnectionsService.java b/stack/services/src/main/java/org/apache/usergrid/services/AbstractConnectionsService.java
index 395f2d4..5f7ca6b 100644
--- a/stack/services/src/main/java/org/apache/usergrid/services/AbstractConnectionsService.java
+++ b/stack/services/src/main/java/org/apache/usergrid/services/AbstractConnectionsService.java
@@ -271,7 +271,7 @@ public class AbstractConnectionsService extends AbstractService {
 
             //TODO T.N. USERGRID-1919 actually validate this is connected
 
-            Entity entity = em.getUniqueEntityFromAlias( query.getEntityType(), name );
+            Entity entity = em.getUniqueEntityFromAlias( query.getEntityType(), name, true);
             if ( entity == null ) {
                 return null;
             }
@@ -372,7 +372,7 @@ public class AbstractConnectionsService extends AbstractService {
             if ( query.containsSingleNameOrEmailIdentifier() ) {
                 String name = query.getSingleNameOrEmailIdentifier();
 
-                entity = em.getUniqueEntityFromAlias( query.getEntityType(), name );
+                entity = em.getUniqueEntityFromAlias( query.getEntityType(), name, true);
                 if ( entity == null ) {
                     throw new ServiceResourceNotFoundException( context );
                 }
@@ -529,7 +529,7 @@ public class AbstractConnectionsService extends AbstractService {
                 nameProperty = "name";
             }
 
-            Entity entity = em.getUniqueEntityFromAlias( query.getEntityType(), name );
+            Entity entity = em.getUniqueEntityFromAlias( query.getEntityType(), name, true);
             if ( entity == null ) {
                 throw new ServiceResourceNotFoundException( context );
             }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/06f77d7b/stack/tools/src/main/java/org/apache/usergrid/tools/UniqueValueScanner.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/main/java/org/apache/usergrid/tools/UniqueValueScanner.java b/stack/tools/src/main/java/org/apache/usergrid/tools/UniqueValueScanner.java
new file mode 100644
index 0000000..f884a1d
--- /dev/null
+++ b/stack/tools/src/main/java/org/apache/usergrid/tools/UniqueValueScanner.java
@@ -0,0 +1,245 @@
+/*
+ * 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.tools;
+
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.UUID;
+
+import com.google.common.base.Optional;
+import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
+import com.netflix.astyanax.model.Column;
+import com.netflix.astyanax.util.RangeBuilder;
+import org.apache.usergrid.persistence.Entity;
+import org.apache.usergrid.persistence.EntityManager;
+import org.apache.usergrid.persistence.collection.MvccEntity;
+import org.apache.usergrid.persistence.collection.serialization.MvccEntitySerializationStrategy;
+import org.apache.usergrid.persistence.collection.serialization.UniqueValueSerializationStrategy;
+import org.apache.usergrid.persistence.collection.serialization.UniqueValueSet;
+import org.apache.usergrid.persistence.collection.serialization.impl.*;
+import org.apache.usergrid.persistence.core.scope.ApplicationScopeImpl;
+import org.apache.usergrid.persistence.model.entity.SimpleId;
+import org.apache.usergrid.persistence.model.field.StringField;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.Options;
+
+
+import org.apache.usergrid.persistence.core.astyanax.MultiTenantColumnFamily;
+import org.apache.usergrid.persistence.core.astyanax.ScopedRowKey;
+import org.apache.usergrid.persistence.core.astyanax.ScopedRowKeySerializer;
+
+
+
+public class UniqueValueScanner extends ToolBase {
+
+    private static final Logger logger = LoggerFactory.getLogger( UniqueValueScanner.class );
+
+    private static final String APPLICATION_ARG = "app";
+
+    private static final String ENTITY_TYPE_ARG = "entityType";
+
+    private static final String ENTITY_NAME_ARG = "entityName";
+
+
+    //copied shamelessly from unique value serialization strat.
+    private static final ScopedRowKeySerializer<TypeField> ROW_KEY_SER =
+        new ScopedRowKeySerializer<>( UniqueTypeFieldRowKeySerializer.get() );
+
+
+    private final EntityVersionSerializer ENTITY_VERSION_SER = new EntityVersionSerializer();
+
+    private final MultiTenantColumnFamily<ScopedRowKey<TypeField>, EntityVersion> CF_UNIQUE_VALUES =
+        new MultiTenantColumnFamily<>( "Unique_Values_V2", ROW_KEY_SER, ENTITY_VERSION_SER );
+
+    private com.netflix.astyanax.Keyspace keyspace;
+
+    private MvccEntitySerializationStrategy mvccEntitySerializationStrategy;
+
+    private UniqueValueSerializationStrategy uniqueValueSerializationStrategy;
+
+    private EntityManager em;
+
+    @Override
+    @SuppressWarnings( "static-access" )
+    public Options createOptions() {
+
+
+        Options options = super.createOptions();
+
+
+        Option appOption = OptionBuilder.withArgName( APPLICATION_ARG ).hasArg().isRequired( true )
+            .withDescription( "application id" ).create( APPLICATION_ARG );
+
+
+        options.addOption( appOption );
+
+        Option collectionOption =
+            OptionBuilder.withArgName(ENTITY_TYPE_ARG).hasArg().isRequired( true ).withDescription( "collection name" )
+                .create(ENTITY_TYPE_ARG);
+
+        options.addOption( collectionOption );
+
+        Option specificEntityNameOption =
+            OptionBuilder.withArgName(ENTITY_NAME_ARG).hasArg().isRequired( true ).withDescription( "specific entity name" )
+                .create(ENTITY_NAME_ARG);
+
+        options.addOption( specificEntityNameOption );
+
+
+        return options;
+    }
+
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see
+     * org.apache.usergrid.tools.ToolBase#runTool(org.apache.commons.cli.CommandLine)
+     */
+    @Override
+    public void runTool( CommandLine line ) throws Exception {
+
+        startSpring();
+
+        UUID appToFilter = null;
+        if (!line.getOptionValue(APPLICATION_ARG).isEmpty()) {
+            appToFilter = UUID.fromString(line.getOptionValue(APPLICATION_ARG));
+        }
+
+
+        logger.info("Starting entity unique scanner");
+
+        keyspace = injector.getInstance(com.netflix.astyanax.Keyspace.class);
+        mvccEntitySerializationStrategy = injector.getInstance(MvccEntitySerializationStrategy.class);
+        uniqueValueSerializationStrategy = injector.getInstance(UniqueValueSerializationStrategy.class);
+
+
+        String entityType = line.getOptionValue(ENTITY_TYPE_ARG);
+        String entityName = line.getOptionValue(ENTITY_NAME_ARG);
+
+        if (entityName != null && !entityName.isEmpty()) {
+
+            if(appToFilter == null){
+                throw new RuntimeException("Cannot execute UniqueValueScanner with specific entity without the " +
+                    "application UUID for which the entity should exist.");
+            }
+
+            if(entityType == null){
+                throw new RuntimeException("Cannot execute UniqueValueScanner without the entity type (singular " +
+                    "collection name).");
+            }
+
+            //do stuff
+            UniqueValueSet uniqueValueSet = uniqueValueSerializationStrategy.load(
+                new ApplicationScopeImpl( new SimpleId(appToFilter, "application" ) ),
+                entityType,
+                Collections.singletonList(new StringField( "name", entityName) ));
+
+            logger.info("Returned unique value set from serialization load = {}", uniqueValueSet);
+
+        } else {
+
+            // scan through all unique values and log some info
+
+            Iterator<com.netflix.astyanax.model.Row<ScopedRowKey<TypeField>, EntityVersion>> rows = null;
+            try {
+
+                rows = keyspace.prepareQuery(CF_UNIQUE_VALUES)
+                    .getAllRows()
+                    .withColumnRange(new RangeBuilder().build())
+                    .execute().getResult().iterator();
+
+            } catch (ConnectionException e) {
+
+            }
+
+
+            UUID finalAppToFilter = appToFilter;
+            rows.forEachRemaining(row -> {
+
+                String fieldName = row.getKey().getKey().getField().getName();
+                String scopeType = row.getKey().getScope().getType();
+                UUID scopeUUID = row.getKey().getScope().getUuid();
+
+                if (!fieldName.equalsIgnoreCase("name") ||
+                    (finalAppToFilter != null && !finalAppToFilter.equals(scopeUUID))
+                    ) {
+                    // do nothing
+
+                } else {
+
+                    if (em == null && finalAppToFilter.equals(scopeUUID)) {
+                        em = emf.getEntityManager(scopeUUID);
+                    }
+
+                    Iterator<Column<EntityVersion>> columns = row.getColumns().iterator();
+                    columns.forEachRemaining(column -> {
+
+                        EntityVersion entityVersion = column.getName();
+
+                        if (entityType != null &&
+                            entityVersion.getEntityId().getType().equalsIgnoreCase(entityType)
+                            ) {
+
+                            String fieldValue = row.getKey().getKey().getField().getValue().toString();
+
+                            logger.trace(
+                                scopeType + ": " + scopeUUID + ", " +
+                                    fieldName + ": " + fieldValue + ", " +
+                                    "entity type: " + entityVersion.getEntityId().getType() + ", " +
+                                    "entity uuid: " + entityVersion.getEntityId().getUuid()
+                            );
+
+
+                            Entity entity = em.getUniqueEntityFromAlias(entityType, fieldValue, false);
+
+//                       Optional<MvccEntity> entity = mvccEntitySerializationStrategy.
+//                            load(new ApplicationScopeImpl(new SimpleId(scopeUUID, scopeType)), entityVersion.getEntityId());
+//
+//                        if(!entity.isPresent()){
+
+                            if (entity == null) {
+
+                                logger.error("{}: {}. Entity with type=[{}],  name=[{}], and uuid=[{}] has a unique value entry " +
+                                        "but cannot be loaded from Mvcc entity serialization",
+                                    scopeType,
+                                    scopeUUID,
+                                    entityVersion.getEntityId().getType(),
+                                    fieldValue,
+                                    entityVersion.getEntityId().getUuid());
+                            }
+
+                        } else {
+                            // do nothing
+                        }
+
+
+                    });
+                }
+
+
+            });
+
+        }
+    }
+}