private void lockKeyedProperty(TitanProperty prop, StoreMutator mutator) throws StorageException {
   TitanKey pt = prop.getPropertyKey();
   assert pt.isSimple();
   if (pt.hasIndex() && pt.isUnique()) {
     if (prop.isNew()) {
       mutator.acquireIndexLock(getIndexKey(prop.getAttribute()), getKeyedIndexColumn(pt), null);
     } else {
       assert prop.isRemoved();
       mutator.acquireIndexLock(
           getIndexKey(prop.getAttribute()), getKeyedIndexColumn(pt), getIndexValue(prop));
     }
   }
 }
 private void addIndexEntry(TitanProperty prop, StoreMutator mutator) throws StorageException {
   TitanKey pt = prop.getPropertyKey();
   assert pt.isSimple();
   if (pt.hasIndex()) {
     if (pt.isUnique()) {
       mutator.mutateIndex(
           getIndexKey(prop.getAttribute()),
           Lists.newArrayList(new Entry(getKeyedIndexColumn(pt), getIndexValue(prop))),
           null);
     } else {
       mutator.mutateIndex(
           getIndexKey(prop.getAttribute()),
           Lists.newArrayList(new Entry(getIndexColumn(pt, prop.getID()), getIndexValue(prop))),
           null);
     }
   }
 }
  private <N extends InternalTitanVertex> void persist(
      ListMultimap<N, InternalRelation> mutatedEdges,
      Map<TitanType, TypeSignature> signatures,
      InternalTitanTransaction tx,
      StoreMutator mutator)
      throws StorageException {
    assert mutatedEdges != null && !mutatedEdges.isEmpty();

    Collection<N> vertices = mutatedEdges.keySet();
    //		if (sortNodes) {
    //			List<N> sortedvertices = new ArrayList<N>(vertices);
    //			Collections.sort(sortedvertices, new Comparator<N>(){
    //
    //				@Override
    //				public int compare(N o1, N o2) {
    //					assert o1.getID()!=o2.getID();
    //					if (o1.getID()<o2.getID()) return -1;
    //					else return 1;
    //				}
    //
    //			});
    //			vertices=sortedvertices;
    //		}

    for (N node : vertices) {
      List<InternalRelation> edges = mutatedEdges.get(node);
      List<Entry> additions = new ArrayList<Entry>(edges.size());
      List<ByteBuffer> deletions = new ArrayList<ByteBuffer>(Math.max(10, edges.size() / 10));
      List<TitanProperty> properties = new ArrayList<TitanProperty>();
      for (InternalRelation edge : edges) {
        if (edge.isRemoved()) {
          if (edge.isProperty()) {
            deleteIndexEntry((TitanProperty) edge, mutator);
          }
          deletions.add(getEntry(tx, edge, node, signatures, true).getColumn());
        } else {
          assert edge.isNew();
          if (edge.isProperty()) properties.add((TitanProperty) edge);
          additions.add(getEntry(tx, edge, node, signatures));
        }
      }
      mutator.mutateEdges(IDHandler.getKey(node.getID()), additions, deletions);
      // Persist property index for retrieval
      for (TitanProperty prop : properties) {
        addIndexEntry(prop, mutator);
      }
    }
  }
  @Override
  public void save(
      final Collection<InternalRelation> addedRelations,
      final Collection<InternalRelation> deletedRelations,
      final InternalTitanTransaction tx)
      throws StorageException {
    // Setup
    log.debug(
        "Saving transaction. Added {}, removed {}", addedRelations.size(), deletedRelations.size());
    final Map<TitanType, TypeSignature> signatures = new HashMap<TitanType, TypeSignature>();
    final TransactionHandle txh = tx.getTxHandle();

    final StoreMutator mutator = getStoreMutator(txh);
    final boolean acquireLocks = tx.getTxConfiguration().hasAcquireLocks();

    // 1. Assign TitanVertex IDs
    assignIDs(addedRelations, tx);

    for (int saveAttempt = 0; saveAttempt < maxWriteRetryAttempts; saveAttempt++) {
      //        while (true) { //Indefinite loop, broken if no exception occurs, otherwise retried
      // or failed immediately
      try {
        // 2. Collect deleted edges
        ListMultimap<InternalTitanVertex, InternalRelation> mutations = ArrayListMultimap.create();
        if (deletedRelations != null && !deletedRelations.isEmpty()) {
          for (InternalRelation del : deletedRelations) {
            assert del.isRemoved();
            for (int pos = 0; pos < del.getArity(); pos++) {
              InternalTitanVertex node = del.getVertex(pos);
              if (pos == 0 || !del.isUnidirected()) {
                mutations.put(node, del);
              }
              if (pos == 0
                  && acquireLocks
                  && del.getType().isFunctional()
                  && ((InternalTitanType) del.getType()).isFunctionalLocking()) {
                Entry entry = getEntry(tx, del, node, signatures);
                mutator.acquireEdgeLock(
                    IDHandler.getKey(node.getID()), entry.getColumn(), entry.getValue());
              }
            }
            if (acquireLocks && del.isProperty()) {
              lockKeyedProperty((TitanProperty) del, mutator);
            }
          }
        }

        ListMultimap<InternalTitanType, InternalRelation> simpleEdgeTypes = null;
        ListMultimap<InternalTitanType, InternalRelation> otherEdgeTypes = null;

        // 3. Sort Added Edges
        for (InternalRelation edge : addedRelations) {
          if (edge.isRemoved()) continue;
          assert edge.isNew();

          TitanType et = edge.getType();

          // Give special treatment to edge type definitions
          if (SystemTypeManager.prepersistedSystemTypes.contains(et)) {
            assert edge.getVertex(0) instanceof InternalTitanType;
            InternalTitanType node = (InternalTitanType) edge.getVertex(0);
            assert node.hasID();
            if (node.isSimple()) {
              if (simpleEdgeTypes == null) simpleEdgeTypes = ArrayListMultimap.create();
              simpleEdgeTypes.put(node, edge);
            } else {
              if (otherEdgeTypes == null) otherEdgeTypes = ArrayListMultimap.create();
              otherEdgeTypes.put(node, edge);
            }
          } else { // STANDARD TitanRelation
            assert (edge.getArity() == 1 && edge.isProperty())
                || (edge.getArity() == 2 && edge.isEdge());
            for (int pos = 0; pos < edge.getArity(); pos++) {
              InternalTitanVertex node = edge.getVertex(pos);
              assert node.hasID();
              if (pos == 0 || !edge.isUnidirected()) {
                mutations.put(node, edge);
              }
              if (pos == 0
                  && acquireLocks
                  && edge.getType().isFunctional()
                  && !node.isNew()
                  && ((InternalTitanType) edge.getType()).isFunctionalLocking()) {
                Entry entry = getEntry(tx, edge, node, signatures, true);
                mutator.acquireEdgeLock(IDHandler.getKey(node.getID()), entry.getColumn(), null);
              }
            }
          }
          if (acquireLocks && edge.isProperty()) {
            lockKeyedProperty((TitanProperty) edge, mutator);
          }
        }

        // 3. Persist
        if (simpleEdgeTypes != null) persist(simpleEdgeTypes, signatures, tx, mutator);
        if (otherEdgeTypes != null) persist(otherEdgeTypes, signatures, tx, mutator);
        mutator.flush();

        // Commit saved EdgeTypes to TypeManager
        if (simpleEdgeTypes != null) commitEdgeTypes(simpleEdgeTypes.keySet());
        if (otherEdgeTypes != null) commitEdgeTypes(otherEdgeTypes.keySet());

        if (!mutations.isEmpty()) persist(mutations, signatures, tx, mutator);
        mutator.flush();

        // Successfully completed - return to break out of loop
        break;
      } catch (Throwable e) {
        if (e instanceof TemporaryStorageException) {
          if (saveAttempt < maxWriteRetryAttempts - 1) temporaryStorageException(e);
          else
            throw new PermanentStorageException(
                "Tried committing "
                    + maxWriteRetryAttempts
                    + " times on temporary exception without success",
                e);
        } else if (e instanceof StorageException) {
          throw (StorageException) e;
        } else {
          throw new PermanentStorageException(
              "Unidentified exception occurred during persistence", e);
        }
      }
    }
  }