/* * 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.mvcc.stage.delete; import java.util.UUID; import org.apache.usergrid.persistence.actorsystem.ActorSystemFig; import org.apache.usergrid.persistence.collection.uniquevalues.UniqueValueException; import org.apache.usergrid.persistence.collection.uniquevalues.UniqueValuesFig; import org.apache.usergrid.persistence.collection.uniquevalues.UniqueValuesService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.usergrid.persistence.collection.MvccEntity; import org.apache.usergrid.persistence.collection.MvccLogEntry; import org.apache.usergrid.persistence.collection.mvcc.entity.MvccValidationUtils; import org.apache.usergrid.persistence.collection.mvcc.entity.Stage; import org.apache.usergrid.persistence.collection.mvcc.entity.impl.MvccLogEntryImpl; import org.apache.usergrid.persistence.collection.mvcc.stage.CollectionIoEvent; import org.apache.usergrid.persistence.collection.serialization.MvccEntitySerializationStrategy; import org.apache.usergrid.persistence.collection.serialization.MvccLogEntrySerializationStrategy; import org.apache.usergrid.persistence.collection.serialization.SerializationFig; import org.apache.usergrid.persistence.collection.serialization.UniqueValueSerializationStrategy; import org.apache.usergrid.persistence.core.scope.ApplicationScope; import org.apache.usergrid.persistence.model.entity.Id; import com.google.common.base.Preconditions; 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 rx.functions.Action1; /** * This phase should invoke any finalization, and mark the entity as committed in the data store before returning */ @Singleton public class MarkCommit implements Action1<CollectionIoEvent<MvccEntity>> { private static final Logger logger = LoggerFactory.getLogger( MarkCommit.class ); private final MvccLogEntrySerializationStrategy logStrat; private final MvccEntitySerializationStrategy entityStrat; private final SerializationFig serializationFig; private final UniqueValueSerializationStrategy uniqueValueStrat; private final Keyspace keyspace; private final ActorSystemFig actorSystemFig; private final UniqueValuesFig uniqueValuesFig; private final UniqueValuesService uniqueValuesService; @Inject public MarkCommit( final MvccLogEntrySerializationStrategy logStrat, final MvccEntitySerializationStrategy entityStrat, final UniqueValueSerializationStrategy uniqueValueStrat, final SerializationFig serializationFig, final ActorSystemFig actorSystemFig, final UniqueValuesFig uniqueValuesFig, final UniqueValuesService uniqueValuesService, final Keyspace keyspace ) { Preconditions.checkNotNull( logStrat, "logEntrySerializationStrategy is required" ); Preconditions.checkNotNull( entityStrat, "entitySerializationStrategy is required" ); this.logStrat = logStrat; this.entityStrat = entityStrat; this.serializationFig = serializationFig; this.uniqueValueStrat = uniqueValueStrat; this.actorSystemFig = actorSystemFig; this.uniqueValuesFig = uniqueValuesFig; this.uniqueValuesService = uniqueValuesService; this.keyspace = keyspace; } @Override public void call( final CollectionIoEvent<MvccEntity> idIoEvent ) { final MvccEntity entity = idIoEvent.getEvent(); MvccValidationUtils.verifyMvccEntityOptionalEntity( entity ); final Id entityId = entity.getId(); final UUID version = entity.getVersion(); final ApplicationScope applicationScope = idIoEvent.getEntityCollection(); logger.debug("Inserting tombstone for entity {} at version {}", entityId, version ); final MvccLogEntry startEntry = new MvccLogEntryImpl( entityId, version, Stage.COMMITTED, MvccLogEntry.State.DELETED ); final MutationBatch entityStateBatch = logStrat.write( applicationScope, startEntry ); //insert a "cleared" value into the versions. Post processing should actually delete try { final MutationBatch entityBatch = entityStrat.mark( applicationScope, entityId, version ); entityStateBatch.mergeShallow( entityBatch ); entityStateBatch.execute(); } catch ( ConnectionException e ) { throw new RuntimeException( "Unable to mark entry as deleted" ); } // TODO: do we need this or can we rely on UniqueCleanup + Cassandra replication? // // // actorSystemFig may be null in testing // if ( actorSystemFig != null && actorSystemFig.getEnabled() ) { // // String region = idIoEvent.getAuthoritativeRegion(); // if ( region == null ) { // region = uniqueValuesFig.getAuthoritativeRegion(); // } // if ( region == null ) { // region = actorSystemFig.getRegionLocal(); // } // // try { // uniqueValuesService.releaseUniqueValues( applicationScope, entityId, version, region ); // } catch (UniqueValueException e) { // throw new RuntimeException( "Unable to release unique values for entity " + entityId ); // } // } } } // // // //TODO Refactor this logic into a a class that can be invoked from anywhere // //load every entity we have history of // Observable<List<MvccEntity>> deleteFieldsObservable = // Observable.create( new ObservableIterator<MvccEntity>( "deleteColumns" ) { // @Override // protected Iterator<MvccEntity> getIterator() { // Iterator<MvccEntity> entities = // entityStrat.load( collectionScope, entityId, entity.getVersion(), 100 ); // // return entities; // } // } ) //buffer them for efficiency // .buffer( serializationFig.getBufferSize() ).doOnNext( // // new Action1<List<MvccEntity>>() { // @Override // public void call( final List<MvccEntity> mvccEntities ) { // // // final MutationBatch batch = keyspace.prepareMutationBatch(); // // for ( MvccEntity mvccEntity : mvccEntities ) { // if ( !mvccEntity.getEntity().isPresent() ) { // continue; // } // // final UUID entityVersion = mvccEntity.getVersion(); // // final Entity entity = mvccEntity.getEntity().get(); // // //remove all unique fields from the index // for ( final Field field : entity.getFields() ) { // // if(!field.isUnique()){ // continue; // } // // final UniqueValue unique = new UniqueValueImpl( field, entityId, entityVersion ); // // final MutationBatch deleteMutation = uniqueValueStrat.delete(collectionScope, unique ); // // batch.mergeShallow( deleteMutation ); // } // } // // try { // batch.execute(); // } // catch ( ConnectionException e1 ) { // throw new RuntimeException( "Unable to execute " + // "unique value " + // "delete", e1 ); // } // } // } // // // ); // // final int removedCount = deleteFieldsObservable.count().toBlocking().last(); // // logger.debug("Removed unique values for {} entities of entity {}", removedCount, entityId );