package mil.nga.giat.geowave.core.store.index; import java.io.Closeable; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import mil.nga.giat.geowave.core.index.ByteArrayId; import mil.nga.giat.geowave.core.store.adapter.statistics.DataStatistics; import mil.nga.giat.geowave.core.store.base.DataStoreEntryInfo; import mil.nga.giat.geowave.core.store.base.DataStoreEntryInfo.FieldInfo; import mil.nga.giat.geowave.core.store.callback.DeleteCallback; import mil.nga.giat.geowave.core.store.callback.IngestCallback; /** * One manager associated with each primary index. * * * @param <T> * The type of entity being indexed */ public class SecondaryIndexDataManager<T> implements Closeable, IngestCallback<T>, DeleteCallback<T> { private final SecondaryIndexDataAdapter<T> adapter; final SecondaryIndexDataStore secondaryIndexStore; final ByteArrayId primaryIndexId; public SecondaryIndexDataManager( final SecondaryIndexDataStore secondaryIndexStore, final SecondaryIndexDataAdapter<T> adapter, final ByteArrayId primaryIndexId ) { this.adapter = adapter; this.secondaryIndexStore = secondaryIndexStore; this.primaryIndexId = primaryIndexId; } @Override public void entryIngested( final DataStoreEntryInfo entryInfo, final T entry ) { // loop secondary indices for adapter for (final SecondaryIndex<T> secondaryIndex : adapter.getSupportedSecondaryIndices()) { final ByteArrayId indexedAttributeFieldId = secondaryIndex.getFieldId(); // get fieldInfo for fieldId to be indexed final FieldInfo<?> indexedAttributeFieldInfo = getFieldInfo( entryInfo, indexedAttributeFieldId); // get indexed value(s) for current field @SuppressWarnings("unchecked") final List<ByteArrayId> secondaryIndexInsertionIds = secondaryIndex.getIndexStrategy().getInsertionIds( Arrays.asList(indexedAttributeFieldInfo)); // loop insertionIds for (final ByteArrayId insertionId : secondaryIndexInsertionIds) { final ByteArrayId primaryIndexRowId = entryInfo.getRowIds().get( 0); final ByteArrayId attributeVisibility = new ByteArrayId( indexedAttributeFieldInfo.getVisibility()); final ByteArrayId dataId = new ByteArrayId( entryInfo.getDataId()); switch (secondaryIndex.getSecondaryIndexType()) { case JOIN: secondaryIndexStore.storeJoinEntry( secondaryIndex.getId(), insertionId, adapter.getAdapterId(), indexedAttributeFieldId, primaryIndexId, primaryIndexRowId, attributeVisibility); break; case PARTIAL: final List<FieldInfo<?>> attributes = new ArrayList<>(); final List<ByteArrayId> attributesToStore = secondaryIndex.getPartialFieldIds(); for (final ByteArrayId fieldId : attributesToStore) { attributes.add(getFieldInfo( entryInfo, fieldId)); } secondaryIndexStore.storeEntry( secondaryIndex.getId(), insertionId, adapter.getAdapterId(), indexedAttributeFieldId, dataId, attributeVisibility, attributes); break; case FULL: secondaryIndexStore.storeEntry( secondaryIndex.getId(), insertionId, adapter.getAdapterId(), indexedAttributeFieldId, dataId, attributeVisibility, // full simply sends over all of the // attributes entryInfo.getFieldInfo()); break; default: break; } } // capture statistics for (final DataStatistics<T> associatedStatistic : secondaryIndex.getAssociatedStatistics()) { associatedStatistic.entryIngested( entryInfo, entry); } } } @Override public void entryDeleted( final DataStoreEntryInfo entryInfo, final T entry ) { // loop secondary indices for adapter for (final SecondaryIndex<T> secondaryIndex : adapter.getSupportedSecondaryIndices()) { final ByteArrayId indexedAttributeFieldId = secondaryIndex.getFieldId(); // get fieldInfo for fieldId to be deleted final FieldInfo<?> indexedAttributeFieldInfo = getFieldInfo( entryInfo, indexedAttributeFieldId); // get indexed value(s) for current field @SuppressWarnings("unchecked") final List<ByteArrayId> secondaryIndexRowIds = secondaryIndex.getIndexStrategy().getInsertionIds( Arrays.asList(indexedAttributeFieldInfo)); // loop insertionIds for (final ByteArrayId secondaryIndexRowId : secondaryIndexRowIds) { final ByteArrayId primaryIndexRowId = entryInfo.getRowIds().get( 0); final ByteArrayId dataId = new ByteArrayId( entryInfo.getDataId()); switch (secondaryIndex.getSecondaryIndexType()) { case JOIN: secondaryIndexStore.deleteJoinEntry( secondaryIndex.getId(), secondaryIndexRowId, adapter.getAdapterId(), indexedAttributeFieldId, primaryIndexId, primaryIndexRowId); break; case PARTIAL: final List<FieldInfo<?>> attributes = new ArrayList<>(); final List<ByteArrayId> attributesToDelete = secondaryIndex.getPartialFieldIds(); for (final ByteArrayId fieldId : attributesToDelete) { attributes.add(getFieldInfo( entryInfo, fieldId)); } secondaryIndexStore.deleteEntry( secondaryIndex.getId(), secondaryIndexRowId, adapter.getAdapterId(), indexedAttributeFieldId, dataId, attributes); break; case FULL: secondaryIndexStore.deleteEntry( secondaryIndex.getId(), secondaryIndexRowId, adapter.getAdapterId(), indexedAttributeFieldId, dataId, // full simply sends over all of the // attributes entryInfo.getFieldInfo()); break; default: break; } } // TODO delete statistics // for (final DataStatistics<T> associatedStatistic : // secondaryIndex.getAssociatedStatistics()) { // associatedStatistic.entryDeleted( // entryInfo, // entry); // } } } private FieldInfo<?> getFieldInfo( final DataStoreEntryInfo entryInfo, final ByteArrayId fieldID ) { for (final FieldInfo<?> info : entryInfo.getFieldInfo()) { if (info.getDataValue().getId().equals( fieldID)) { return info; } } return null; } @Override public void close() throws IOException { if (secondaryIndexStore != null) { secondaryIndexStore.flush(); } } }