use of com.thinkaurelius.titan.graphdb.types.MixedIndexType in project titan by thinkaurelius.
the class StandardTitanGraph method prepareCommit.
public ModificationSummary prepareCommit(final Collection<InternalRelation> addedRelations, final Collection<InternalRelation> deletedRelations, final Predicate<InternalRelation> filter, final BackendTransaction mutator, final StandardTitanTx tx, final boolean acquireLocks) throws BackendException {
ListMultimap<Long, InternalRelation> mutations = ArrayListMultimap.create();
ListMultimap<InternalVertex, InternalRelation> mutatedProperties = ArrayListMultimap.create();
List<IndexSerializer.IndexUpdate> indexUpdates = Lists.newArrayList();
//1) Collect deleted edges and their index updates and acquire edge locks
for (InternalRelation del : Iterables.filter(deletedRelations, filter)) {
Preconditions.checkArgument(del.isRemoved());
for (int pos = 0; pos < del.getLen(); pos++) {
InternalVertex vertex = del.getVertex(pos);
if (pos == 0 || !del.isLoop()) {
if (del.isProperty())
mutatedProperties.put(vertex, del);
mutations.put(vertex.longId(), del);
}
if (acquireLock(del, pos, acquireLocks)) {
Entry entry = edgeSerializer.writeRelation(del, pos, tx);
mutator.acquireEdgeLock(idManager.getKey(vertex.longId()), entry);
}
}
indexUpdates.addAll(indexSerializer.getIndexUpdates(del));
}
//2) Collect added edges and their index updates and acquire edge locks
for (InternalRelation add : Iterables.filter(addedRelations, filter)) {
Preconditions.checkArgument(add.isNew());
for (int pos = 0; pos < add.getLen(); pos++) {
InternalVertex vertex = add.getVertex(pos);
if (pos == 0 || !add.isLoop()) {
if (add.isProperty())
mutatedProperties.put(vertex, add);
mutations.put(vertex.longId(), add);
}
if (!vertex.isNew() && acquireLock(add, pos, acquireLocks)) {
Entry entry = edgeSerializer.writeRelation(add, pos, tx);
mutator.acquireEdgeLock(idManager.getKey(vertex.longId()), entry.getColumn());
}
}
indexUpdates.addAll(indexSerializer.getIndexUpdates(add));
}
//3) Collect all index update for vertices
for (InternalVertex v : mutatedProperties.keySet()) {
indexUpdates.addAll(indexSerializer.getIndexUpdates(v, mutatedProperties.get(v)));
}
//4) Acquire index locks (deletions first)
for (IndexSerializer.IndexUpdate update : indexUpdates) {
if (!update.isCompositeIndex() || !update.isDeletion())
continue;
CompositeIndexType iIndex = (CompositeIndexType) update.getIndex();
if (acquireLock(iIndex, acquireLocks)) {
mutator.acquireIndexLock((StaticBuffer) update.getKey(), (Entry) update.getEntry());
}
}
for (IndexSerializer.IndexUpdate update : indexUpdates) {
if (!update.isCompositeIndex() || !update.isAddition())
continue;
CompositeIndexType iIndex = (CompositeIndexType) update.getIndex();
if (acquireLock(iIndex, acquireLocks)) {
mutator.acquireIndexLock((StaticBuffer) update.getKey(), ((Entry) update.getEntry()).getColumn());
}
}
//5) Add relation mutations
for (Long vertexid : mutations.keySet()) {
Preconditions.checkArgument(vertexid > 0, "Vertex has no id: %s", vertexid);
List<InternalRelation> edges = mutations.get(vertexid);
List<Entry> additions = new ArrayList<Entry>(edges.size());
List<Entry> deletions = new ArrayList<Entry>(Math.max(10, edges.size() / 10));
for (InternalRelation edge : edges) {
InternalRelationType baseType = (InternalRelationType) edge.getType();
assert baseType.getBaseType() == null;
for (InternalRelationType type : baseType.getRelationIndexes()) {
if (type.getStatus() == SchemaStatus.DISABLED)
continue;
for (int pos = 0; pos < edge.getArity(); pos++) {
if (!type.isUnidirected(Direction.BOTH) && !type.isUnidirected(EdgeDirection.fromPosition(pos)))
//Directionality is not covered
continue;
if (edge.getVertex(pos).longId() == vertexid) {
StaticArrayEntry entry = edgeSerializer.writeRelation(edge, type, pos, tx);
if (edge.isRemoved()) {
deletions.add(entry);
} else {
Preconditions.checkArgument(edge.isNew());
int ttl = getTTL(edge);
if (ttl > 0) {
entry.setMetaData(EntryMetaData.TTL, ttl);
}
additions.add(entry);
}
}
}
}
}
StaticBuffer vertexKey = idManager.getKey(vertexid);
mutator.mutateEdges(vertexKey, additions, deletions);
}
//6) Add index updates
boolean has2iMods = false;
for (IndexSerializer.IndexUpdate indexUpdate : indexUpdates) {
assert indexUpdate.isAddition() || indexUpdate.isDeletion();
if (indexUpdate.isCompositeIndex()) {
IndexSerializer.IndexUpdate<StaticBuffer, Entry> update = indexUpdate;
if (update.isAddition())
mutator.mutateIndex(update.getKey(), Lists.newArrayList(update.getEntry()), KCVSCache.NO_DELETIONS);
else
mutator.mutateIndex(update.getKey(), KeyColumnValueStore.NO_ADDITIONS, Lists.newArrayList(update.getEntry()));
} else {
IndexSerializer.IndexUpdate<String, IndexEntry> update = indexUpdate;
has2iMods = true;
IndexTransaction itx = mutator.getIndexTransaction(update.getIndex().getBackingIndexName());
String indexStore = ((MixedIndexType) update.getIndex()).getStoreName();
if (update.isAddition())
itx.add(indexStore, update.getKey(), update.getEntry(), update.getElement().isNew());
else
itx.delete(indexStore, update.getKey(), update.getEntry().field, update.getEntry().value, update.getElement().isRemoved());
}
}
return new ModificationSummary(!mutations.isEmpty(), has2iMods);
}
use of com.thinkaurelius.titan.graphdb.types.MixedIndexType in project titan by thinkaurelius.
the class ManagementSystem method addIndexKey.
@Override
public void addIndexKey(final TitanGraphIndex index, final PropertyKey key, Parameter... parameters) {
Preconditions.checkArgument(index != null && key != null && index instanceof TitanGraphIndexWrapper && !(key instanceof BaseKey), "Need to provide valid index and key");
if (parameters == null)
parameters = new Parameter[0];
IndexType indexType = ((TitanGraphIndexWrapper) index).getBaseIndex();
Preconditions.checkArgument(indexType instanceof MixedIndexType, "Can only add keys to an external index, not %s", index.name());
Preconditions.checkArgument(indexType instanceof IndexTypeWrapper && key instanceof TitanSchemaVertex && ((IndexTypeWrapper) indexType).getSchemaBase() instanceof TitanSchemaVertex);
TitanSchemaVertex indexVertex = (TitanSchemaVertex) ((IndexTypeWrapper) indexType).getSchemaBase();
for (IndexField field : indexType.getFieldKeys()) Preconditions.checkArgument(!field.getFieldKey().equals(key), "Key [%s] has already been added to index %s", key.name(), index.name());
//Assemble parameters
boolean addMappingParameter = !ParameterType.MAPPED_NAME.hasParameter(parameters);
Parameter[] extendedParas = new Parameter[parameters.length + 1 + (addMappingParameter ? 1 : 0)];
System.arraycopy(parameters, 0, extendedParas, 0, parameters.length);
int arrPosition = parameters.length;
if (addMappingParameter)
extendedParas[arrPosition++] = ParameterType.MAPPED_NAME.getParameter(graph.getIndexSerializer().getDefaultFieldName(key, parameters, indexType.getBackingIndexName()));
extendedParas[arrPosition++] = ParameterType.STATUS.getParameter(key.isNew() ? SchemaStatus.ENABLED : SchemaStatus.INSTALLED);
addSchemaEdge(indexVertex, key, TypeDefinitionCategory.INDEX_FIELD, extendedParas);
updateSchemaVertex(indexVertex);
indexType.resetCache();
//Check to see if the index supports this
if (!graph.getIndexSerializer().supports((MixedIndexType) indexType, ParameterIndexField.of(key, parameters))) {
throw new TitanException("Could not register new index field '" + key.name() + "' with index backend as the data type, cardinality or parameter combination is not supported.");
}
try {
IndexSerializer.register((MixedIndexType) indexType, key, transaction.getTxHandle());
} catch (BackendException e) {
throw new TitanException("Could not register new index field with index backend", e);
}
if (!indexVertex.isNew())
updatedTypes.add(indexVertex);
if (!key.isNew())
updateIndex(index, SchemaAction.REGISTER_INDEX);
}
use of com.thinkaurelius.titan.graphdb.types.MixedIndexType in project titan by thinkaurelius.
the class StandardTransactionLogProcessor method fixSecondaryFailure.
private void fixSecondaryFailure(final StandardTransactionId txId, final TxEntry entry) {
logRecoveryMsg("Attempting to repair partially failed transaction [%s]", txId);
if (entry.entry == null) {
logRecoveryMsg("Trying to repair expired or unpersisted transaction [%s] (Ignore in startup)", txId);
return;
}
boolean userLogFailure = true;
boolean secIndexFailure = true;
final Predicate<String> isFailedIndex;
final TransactionLogHeader.Entry commitEntry = entry.entry;
final TransactionLogHeader.SecondaryFailures secFail = entry.failures;
if (secFail != null) {
userLogFailure = secFail.userLogFailure;
secIndexFailure = !secFail.failedIndexes.isEmpty();
isFailedIndex = new Predicate<String>() {
@Override
public boolean apply(@Nullable String s) {
return secFail.failedIndexes.contains(s);
}
};
} else {
isFailedIndex = Predicates.alwaysTrue();
}
// I) Restore external indexes
if (secIndexFailure) {
//1) Collect all elements (vertices and relations) and the indexes for which they need to be restored
final SetMultimap<String, IndexRestore> indexRestores = HashMultimap.create();
BackendOperation.execute(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
StandardTitanTx tx = (StandardTitanTx) graph.newTransaction();
try {
for (TransactionLogHeader.Modification modification : commitEntry.getContentAsModifications(serializer)) {
InternalRelation rel = ModificationDeserializer.parseRelation(modification, tx);
//Collect affected vertex indexes
for (MixedIndexType index : getMixedIndexes(rel.getType())) {
if (index.getElement() == ElementCategory.VERTEX && isFailedIndex.apply(index.getBackingIndexName())) {
assert rel.isProperty();
indexRestores.put(index.getBackingIndexName(), new IndexRestore(rel.getVertex(0).longId(), ElementCategory.VERTEX, getIndexId(index)));
}
}
//See if relation itself is affected
for (RelationType relType : rel.getPropertyKeysDirect()) {
for (MixedIndexType index : getMixedIndexes(relType)) {
if (index.getElement().isInstance(rel) && isFailedIndex.apply(index.getBackingIndexName())) {
assert rel.id() instanceof RelationIdentifier;
indexRestores.put(index.getBackingIndexName(), new IndexRestore(rel.id(), ElementCategory.getByClazz(rel.getClass()), getIndexId(index)));
}
}
}
}
} finally {
if (tx.isOpen())
tx.rollback();
}
return true;
}
}, readTime);
//2) Restore elements per backing index
for (final String indexName : indexRestores.keySet()) {
final StandardTitanTx tx = (StandardTitanTx) graph.newTransaction();
try {
BackendTransaction btx = tx.getTxHandle();
final IndexTransaction indexTx = btx.getIndexTransaction(indexName);
BackendOperation.execute(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
Map<String, Map<String, List<IndexEntry>>> restoredDocs = Maps.newHashMap();
for (IndexRestore restore : indexRestores.get(indexName)) {
TitanSchemaVertex indexV = (TitanSchemaVertex) tx.getVertex(restore.indexId);
MixedIndexType index = (MixedIndexType) indexV.asIndexType();
TitanElement element = restore.retrieve(tx);
if (element != null) {
graph.getIndexSerializer().reindexElement(element, index, restoredDocs);
} else {
//Element is deleted
graph.getIndexSerializer().removeElement(restore.elementId, index, restoredDocs);
}
}
indexTx.restore(restoredDocs);
indexTx.commit();
return true;
}
@Override
public String toString() {
return "IndexMutation";
}
}, persistenceTime);
} finally {
if (tx.isOpen())
tx.rollback();
}
}
}
// II) Restore log messages
final String logTxIdentifier = (String) commitEntry.getMetadata().get(LogTxMeta.LOG_ID);
if (userLogFailure && logTxIdentifier != null) {
TransactionLogHeader txHeader = new TransactionLogHeader(txCounter.incrementAndGet(), times.getTime(), times);
final StaticBuffer userLogContent = txHeader.serializeUserLog(serializer, commitEntry, txId);
BackendOperation.execute(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
final Log userLog = graph.getBackend().getUserLog(logTxIdentifier);
Future<Message> env = userLog.add(userLogContent);
if (env.isDone()) {
env.get();
}
return true;
}
}, persistenceTime);
}
}
use of com.thinkaurelius.titan.graphdb.types.MixedIndexType in project titan by thinkaurelius.
the class ManagementSystem method updateIndex.
/* --------------
Schema Update
--------------- */
@Override
public IndexJobFuture updateIndex(TitanIndex index, SchemaAction updateAction) {
Preconditions.checkArgument(index != null, "Need to provide an index");
Preconditions.checkArgument(updateAction != null, "Need to provide update action");
TitanSchemaVertex schemaVertex = getSchemaVertex(index);
Set<TitanSchemaVertex> dependentTypes;
Set<PropertyKeyVertex> keySubset = ImmutableSet.of();
if (index instanceof RelationTypeIndex) {
dependentTypes = ImmutableSet.of((TitanSchemaVertex) ((InternalRelationType) schemaVertex).getBaseType());
if (!updateAction.isApplicableStatus(schemaVertex.getStatus()))
return null;
} else if (index instanceof TitanGraphIndex) {
IndexType indexType = schemaVertex.asIndexType();
dependentTypes = Sets.newHashSet();
if (indexType.isCompositeIndex()) {
if (!updateAction.isApplicableStatus(schemaVertex.getStatus()))
return null;
for (PropertyKey key : ((TitanGraphIndex) index).getFieldKeys()) {
dependentTypes.add((PropertyKeyVertex) key);
}
} else {
keySubset = Sets.newHashSet();
MixedIndexType cindexType = (MixedIndexType) indexType;
Set<SchemaStatus> applicableStatus = updateAction.getApplicableStatus();
for (ParameterIndexField field : cindexType.getFieldKeys()) {
if (applicableStatus.contains(field.getStatus()))
keySubset.add((PropertyKeyVertex) field.getFieldKey());
}
if (keySubset.isEmpty())
return null;
dependentTypes.addAll(keySubset);
}
} else
throw new UnsupportedOperationException("Updates not supported for index: " + index);
IndexIdentifier indexId = new IndexIdentifier(index);
StandardScanner.Builder builder;
IndexJobFuture future;
switch(updateAction) {
case REGISTER_INDEX:
setStatus(schemaVertex, SchemaStatus.INSTALLED, keySubset);
updatedTypes.add(schemaVertex);
updatedTypes.addAll(dependentTypes);
setUpdateTrigger(new UpdateStatusTrigger(graph, schemaVertex, SchemaStatus.REGISTERED, keySubset));
future = new EmptyIndexJobFuture();
break;
case REINDEX:
builder = graph.getBackend().buildEdgeScanJob();
builder.setFinishJob(indexId.getIndexJobFinisher(graph, SchemaAction.ENABLE_INDEX));
builder.setJobId(indexId);
builder.setJob(VertexJobConverter.convert(graph, new IndexRepairJob(indexId.indexName, indexId.relationTypeName)));
try {
future = builder.execute();
} catch (BackendException e) {
throw new TitanException(e);
}
break;
case ENABLE_INDEX:
setStatus(schemaVertex, SchemaStatus.ENABLED, keySubset);
updatedTypes.add(schemaVertex);
if (!keySubset.isEmpty())
updatedTypes.addAll(dependentTypes);
future = new EmptyIndexJobFuture();
break;
case DISABLE_INDEX:
setStatus(schemaVertex, SchemaStatus.INSTALLED, keySubset);
updatedTypes.add(schemaVertex);
if (!keySubset.isEmpty())
updatedTypes.addAll(dependentTypes);
setUpdateTrigger(new UpdateStatusTrigger(graph, schemaVertex, SchemaStatus.DISABLED, keySubset));
future = new EmptyIndexJobFuture();
break;
case REMOVE_INDEX:
if (index instanceof RelationTypeIndex) {
builder = graph.getBackend().buildEdgeScanJob();
} else {
TitanGraphIndex gindex = (TitanGraphIndex) index;
if (gindex.isMixedIndex())
throw new UnsupportedOperationException("External mixed indexes must be removed in the indexing system directly.");
builder = graph.getBackend().buildGraphIndexScanJob();
}
builder.setFinishJob(indexId.getIndexJobFinisher());
builder.setJobId(indexId);
builder.setJob(new IndexRemoveJob(graph, indexId.indexName, indexId.relationTypeName));
try {
future = builder.execute();
} catch (BackendException e) {
throw new TitanException(e);
}
break;
default:
throw new UnsupportedOperationException("Update action not supported: " + updateAction);
}
return future;
}
use of com.thinkaurelius.titan.graphdb.types.MixedIndexType in project titan by thinkaurelius.
the class IndexRepairJob method process.
@Override
public void process(TitanVertex vertex, ScanMetrics metrics) {
try {
BackendTransaction mutator = writeTx.getTxHandle();
if (index instanceof RelationTypeIndex) {
RelationTypeIndexWrapper wrapper = (RelationTypeIndexWrapper) index;
InternalRelationType wrappedType = wrapper.getWrappedType();
EdgeSerializer edgeSerializer = writeTx.getEdgeSerializer();
List<Entry> additions = new ArrayList<>();
for (TitanRelation relation : vertex.query().types(indexRelationTypeName).direction(Direction.OUT).relations()) {
InternalRelation titanRelation = (InternalRelation) relation;
for (int pos = 0; pos < titanRelation.getArity(); pos++) {
if (!wrappedType.isUnidirected(Direction.BOTH) && !wrappedType.isUnidirected(EdgeDirection.fromPosition(pos)))
//Directionality is not covered
continue;
Entry entry = edgeSerializer.writeRelation(titanRelation, wrappedType, pos, writeTx);
additions.add(entry);
}
}
StaticBuffer vertexKey = writeTx.getIdInspector().getKey(vertex.longId());
mutator.mutateEdges(vertexKey, additions, KCVSCache.NO_DELETIONS);
metrics.incrementCustom(ADDED_RECORDS_COUNT, additions.size());
} else if (index instanceof TitanGraphIndex) {
IndexType indexType = mgmt.getSchemaVertex(index).asIndexType();
assert indexType != null;
IndexSerializer indexSerializer = graph.getIndexSerializer();
//Gather elements to index
List<TitanElement> elements;
switch(indexType.getElement()) {
case VERTEX:
elements = ImmutableList.of(vertex);
break;
case PROPERTY:
elements = Lists.newArrayList();
for (TitanVertexProperty p : addIndexSchemaConstraint(vertex.query(), indexType).properties()) {
elements.add(p);
}
break;
case EDGE:
elements = Lists.newArrayList();
for (TitanEdge e : addIndexSchemaConstraint(vertex.query().direction(Direction.OUT), indexType).edges()) {
elements.add(e);
}
break;
default:
throw new AssertionError("Unexpected category: " + indexType.getElement());
}
if (indexType.isCompositeIndex()) {
for (TitanElement element : elements) {
Set<IndexSerializer.IndexUpdate<StaticBuffer, Entry>> updates = indexSerializer.reindexElement(element, (CompositeIndexType) indexType);
for (IndexSerializer.IndexUpdate<StaticBuffer, Entry> update : updates) {
log.debug("Mutating index {}: {}", indexType, update.getEntry());
mutator.mutateIndex(update.getKey(), Lists.newArrayList(update.getEntry()), KCVSCache.NO_DELETIONS);
metrics.incrementCustom(ADDED_RECORDS_COUNT);
}
}
} else {
assert indexType.isMixedIndex();
Map<String, Map<String, List<IndexEntry>>> documentsPerStore = new HashMap<>();
for (TitanElement element : elements) {
indexSerializer.reindexElement(element, (MixedIndexType) indexType, documentsPerStore);
metrics.incrementCustom(DOCUMENT_UPDATES_COUNT);
}
mutator.getIndexTransaction(indexType.getBackingIndexName()).restore(documentsPerStore);
}
} else
throw new UnsupportedOperationException("Unsupported index found: " + index);
} catch (final Exception e) {
mgmt.rollback();
writeTx.rollback();
metrics.incrementCustom(FAILED_TX);
throw new TitanException(e.getMessage(), e);
}
}
Aggregations