private Entry getEntry(
      InternalTitanTransaction tx,
      InternalRelation edge,
      InternalTitanVertex perspective,
      Map<TitanType, TypeSignature> signatures,
      boolean columnOnly) {
    TitanType et = edge.getType();
    long etid = et.getID();

    int dirID;
    if (edge.isProperty()) {
      dirID = 0;
    } else if (edge.getVertex(0).equals(perspective)) {
      // Out TitanRelation
      assert edge.isDirected() || edge.isUnidirected();
      dirID = 2;
    } else {
      // In TitanRelation
      assert !edge.isUnidirected() && edge.getVertex(1).equals(perspective);
      dirID = 3;
    }

    int etIDLength = IDHandler.edgeTypeLength(etid, idManager);

    ByteBuffer column = null, value = null;
    if (et.isSimple()) {
      if (et.isFunctional()) {
        column = ByteBuffer.allocate(etIDLength);
        IDHandler.writeEdgeType(column, etid, dirID, idManager);
      } else {
        column = ByteBuffer.allocate(etIDLength + VariableLong.positiveLength(edge.getID()));
        IDHandler.writeEdgeType(column, etid, dirID, idManager);
        VariableLong.writePositive(column, edge.getID());
      }
      column.flip();
      if (!columnOnly) {
        if (edge.isEdge()) {
          long nodeIDDiff =
              ((TitanEdge) edge).getOtherVertex(perspective).getID() - perspective.getID();
          int nodeIDDiffLength = VariableLong.length(nodeIDDiff);
          if (et.isFunctional()) {
            value =
                ByteBuffer.allocate(nodeIDDiffLength + VariableLong.positiveLength(edge.getID()));
            VariableLong.write(value, nodeIDDiff);
            VariableLong.writePositive(value, edge.getID());
          } else {
            value = ByteBuffer.allocate(nodeIDDiffLength);
            VariableLong.write(value, nodeIDDiff);
          }
          value.flip();
        } else {
          assert edge.isProperty();
          DataOutput out = serializer.getDataOutput(defaultOutputCapacity, true);
          // Write object
          writeAttribute(out, (TitanProperty) edge);
          if (et.isFunctional()) {
            VariableLong.writePositive(out, edge.getID());
          }
          value = out.getByteBuffer();
        }
      }
    } else {
      TypeSignature ets = getSignature(tx, et, signatures);

      InternalRelation[] keys = new InternalRelation[ets.keyLength()],
          values = new InternalRelation[ets.valueLength()];
      List<InternalRelation> rest = new ArrayList<InternalRelation>();
      ets.sort(edge.getRelations(SimpleAtomicQuery.queryAll(edge), false), keys, values, rest);

      DataOutput out = serializer.getDataOutput(defaultOutputCapacity, true);
      IDHandler.writeEdgeType(out, etid, dirID, idManager);

      for (int i = 0; i < keys.length; i++) writeInlineEdge(out, keys[i], ets.getKeyType(i));

      if (!et.isFunctional()) {
        VariableLong.writePositive(out, edge.getID());
      }
      column = out.getByteBuffer();

      if (!columnOnly) {
        out = serializer.getDataOutput(defaultOutputCapacity, true);

        if (edge.isEdge()) {
          long nodeIDDiff =
              ((TitanEdge) edge).getOtherVertex(perspective).getID() - perspective.getID();
          VariableLong.write(out, nodeIDDiff);
        } else {
          assert edge.isProperty();
          writeAttribute(out, (TitanProperty) edge);
        }

        if (et.isFunctional()) {
          assert edge.isEdge();
          VariableLong.writePositive(out, edge.getID());
        }
        for (int i = 0; i < values.length; i++)
          writeInlineEdge(out, values[i], ets.getValueType(i));
        for (InternalRelation v : rest) writeInlineEdge(out, v);
        value = out.getByteBuffer();
      }
    }
    return new Entry(column, value);
  }
  protected void loadRelations(
      Iterable<Entry> entries, VertexRelationLoader loader, InternalTitanTransaction tx) {
    Map<String, TitanType> etCache = new HashMap<String, TitanType>();
    TitanType titanType = null;

    for (Entry entry : entries) {
      ByteBuffer column = entry.getColumn();
      int dirID = IDHandler.getDirectionID(column.get(column.position()));
      long etid = IDHandler.readEdgeType(column, idManager);

      if (titanType == null || titanType.getID() != etid) {
        titanType = getTypeFromID(etid, tx);
      }

      Object[] keys = null;
      if (!titanType.isSimple()) {
        TypeDefinition def = ((InternalTitanType) titanType).getDefinition();
        String[] keysig = def.getKeySignature();
        keys = new Object[keysig.length];
        for (int i = 0; i < keysig.length; i++)
          keys[i] = readInline(column, getEdgeType(keysig[i], etCache, tx));
      }

      long edgeid = 0;
      if (!titanType.isFunctional()) {
        edgeid = VariableLong.readPositive(column);
      }

      ByteBuffer value = entry.getValue();
      if (titanType.isEdgeLabel()) {
        long nodeIDDiff = VariableLong.read(value);
        if (titanType.isFunctional()) edgeid = VariableLong.readPositive(value);
        assert edgeid > 0;
        long otherid = loader.getVertexId() + nodeIDDiff;
        assert dirID == 3 || dirID == 2;
        Direction dir = dirID == 3 ? Direction.IN : Direction.OUT;
        if (!tx.isDeletedRelation(edgeid))
          loader.loadEdge(edgeid, (TitanLabel) titanType, dir, otherid);
      } else {
        assert titanType.isPropertyKey();
        assert dirID == 0;
        TitanKey propType = ((TitanKey) titanType);
        Object attribute = null;

        if (hasGenericDataType(propType)) {
          attribute = serializer.readClassAndObject(value);
        } else {
          attribute = serializer.readObjectNotNull(value, propType.getDataType());
        }
        assert attribute != null;

        if (titanType.isFunctional()) edgeid = VariableLong.readPositive(value);
        assert edgeid > 0;
        if (!tx.isDeletedRelation(edgeid)) loader.loadProperty(edgeid, propType, attribute);
      }

      // Read value inline edges if any
      if (!titanType.isSimple()) {
        TypeDefinition def = ((InternalTitanType) titanType).getDefinition();
        // First create all keys buffered above
        String[] keysig = def.getKeySignature();
        for (int i = 0; i < keysig.length; i++) {
          createInlineEdge(loader, getEdgeType(keysig[i], etCache, tx), keys[i]);
        }

        // value signature
        for (String str : def.getCompactSignature())
          readLabel(loader, value, getEdgeType(str, etCache, tx));

        // Third: read rest
        while (value.hasRemaining()) {
          TitanType type =
              (TitanType) tx.getExistingVertex(IDHandler.readInlineEdgeType(value, idManager));
          readLabel(loader, value, type);
        }
      }
    }
  }