All Downloads are FREE. Search and download functionalities are using the official Maven repository.

overflowdb.storage.NodeDeserializer Maven / Gradle / Ivy

package overflowdb.storage;

import org.msgpack.core.MessagePack;
import org.msgpack.core.MessageUnpacker;
import org.msgpack.value.ArrayValue;
import org.msgpack.value.ImmutableValue;
import org.msgpack.value.Value;
import overflowdb.Direction;
import overflowdb.Graph;
import overflowdb.NodeDb;
import overflowdb.NodeFactory;
import overflowdb.NodeRef;
import overflowdb.util.PropertyHelper;
import overflowdb.util.StringInterner;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class NodeDeserializer extends BookKeeper {
  protected final Graph graph;
  private final Map nodeFactoryByLabel;
  private final OdbStorage storage;
  private final StringInterner stringInterner;

  public NodeDeserializer(Graph graph, Map nodeFactoryByLabel, boolean statsEnabled, OdbStorage storage) {
    super(statsEnabled);
    this.graph = graph;
    this.stringInterner = graph.getStringInterner();
    this.nodeFactoryByLabel = nodeFactoryByLabel;
    this.storage = storage;
  }

  public final NodeDb deserialize(byte[] bytes) throws  IOException {
    return deserialize(bytes, null);
  }
  public final NodeDb deserialize(byte[] bytes, NodeRef ref) throws IOException {
    long startTimeNanos = getStartTimeNanos();
    if (null == bytes)
      return null;

    MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(bytes);
    final long id = unpacker.unpackLong();
    final int labelStringId = unpacker.unpackInt();
    final Object[] properties = unpackProperties(unpacker);

    final String label = storage.reverseLookupStringToIntMapping(labelStringId);
    NodeDb node = getNodeFactory(label).createNode(graph, id, ref);
    PropertyHelper.attachProperties(node, properties);

    deserializeEdges(unpacker, node, Direction.OUT);
    deserializeEdges(unpacker, node, Direction.IN);

    node.markAsClean();

    if (statsEnabled) recordStatistics(startTimeNanos);
    return node;
  }

  private void deserializeEdges(MessageUnpacker unpacker, NodeDb node, Direction direction) throws IOException {
    int edgeTypesCount = unpacker.unpackInt();
    for (int edgeTypeIdx = 0; edgeTypeIdx < edgeTypesCount; edgeTypeIdx++) {
      int edgeLabelId = unpacker.unpackInt();
      String edgeLabel = storage.reverseLookupStringToIntMapping(edgeLabelId);
      int edgeCount = unpacker.unpackInt();
      for (int edgeIdx = 0; edgeIdx < edgeCount; edgeIdx++) {
        long adjacentNodeId = unpacker.unpackLong();
        NodeRef adjacentNode = (NodeRef) graph.node(adjacentNodeId);
        Object[] edgeProperties = unpackProperties(unpacker);
        node.storeAdjacentNode(direction, edgeLabel, adjacentNode, edgeProperties);
      }
    }
  }

  /**
   * only deserialize the part we're keeping in memory, used during startup when initializing from disk
   */
  public final NodeRef deserializeRef(byte[] bytes) throws IOException {
    try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(bytes)) {
      long id = unpacker.unpackLong();
      int labelStringId = unpacker.unpackInt();
      String label = storage.reverseLookupStringToIntMapping(labelStringId);

      return createNodeRef(id, label);
    }
  }

  private final Object[] unpackProperties(MessageUnpacker unpacker) throws IOException {
    int propertyCount = unpacker.unpackMapHeader();
    Object[] res = new Object[propertyCount * 2];
    int resIdx = 0;
    for (int propertyIdx = 0; propertyIdx < propertyCount; propertyIdx++) {
      int keyId = unpacker.unpackInt();
      final String key = storage.reverseLookupStringToIntMapping(keyId);
      final ImmutableValue unpackedValue = unpacker.unpackValue();
      final Object unpackedProperty = unpackValue(unpackedValue.asArrayValue());
      res[resIdx++] = key;
      res[resIdx++] = unpackedProperty;
    }
    return res;
  }

  private final Object unpackValue(final ArrayValue packedValueAndType) {
    final Iterator iter = packedValueAndType.iterator();
   final byte valueTypeId = iter.next().asIntegerValue().asByte();
    final Value value = iter.next();

    switch (ValueTypes.lookup(valueTypeId)) {
      case UNKNOWN:
        return null;
      case NODE_REF:
        long id = value.asIntegerValue().asLong();
        return graph.node(id);
      case BOOLEAN:
        return value.asBooleanValue().getBoolean();
      case STRING:
        return stringInterner.intern(value.asStringValue().asString());
      case BYTE:
        return value.asIntegerValue().asByte();
      case SHORT:
        return value.asIntegerValue().asShort();
      case INTEGER:
        return value.asIntegerValue().asInt();
      case LONG:
        return value.asIntegerValue().asLong();
      case FLOAT:
        return value.asFloatValue().toFloat();
      case DOUBLE:
        return value.asFloatValue().toDouble();
      case LIST:
        return deserializeList(value.asArrayValue());
      case CHARACTER:
        return (char) value.asIntegerValue().asInt();
      case ARRAY_BYTE:
        return deserializeArrayByte(value.asArrayValue());
      case ARRAY_SHORT:
        return deserializeArrayShort(value.asArrayValue());
      case ARRAY_INT:
        return deserializeArrayInt(value.asArrayValue());
      case ARRAY_LONG:
        return deserializeArrayLong(value.asArrayValue());
      case ARRAY_FLOAT:
        return deserializeArrayFloat(value.asArrayValue());
      case ARRAY_DOUBLE:
        return deserializeArrayDouble(value.asArrayValue());
      case ARRAY_CHAR:
        return deserializeArrayChar(value.asArrayValue());
      case ARRAY_BOOL:
        return deserializeArrayBoolean(value.asArrayValue());
      case ARRAY_OBJECT:
        return deserializeArrayObject(value.asArrayValue());
      default:
        throw new UnsupportedOperationException("unknown valueTypeId=`" + valueTypeId);
    }
  }

  protected final NodeRef createNodeRef(long id, String label) {
    return getNodeFactory(label).createNodeRef(graph, id);
  }

  private final NodeFactory getNodeFactory(String label) {
    if (!nodeFactoryByLabel.containsKey(label))
      throw new AssertionError(String.format("nodeFactory not found for label=%s", label));

    return nodeFactoryByLabel.get(label);
  }

  /** only keeping for legacy reasons, going forward, all lists are stored as arrays */
  private Object deserializeList(ArrayValue arrayValue) {
    final List deserializedList = new ArrayList(arrayValue.size());
    final Iterator valueIterator = arrayValue.iterator();
    while (valueIterator.hasNext()) {
      deserializedList.add(unpackValue(valueIterator.next().asArrayValue()));
    }
    return deserializedList;
  }

  private byte[] deserializeArrayByte(ArrayValue arrayValue) {
    byte[] deserializedArray = new byte[arrayValue.size()];
    int idx = 0;
    final Iterator valueIterator = arrayValue.iterator();
    while (valueIterator.hasNext()) {
      deserializedArray[idx++] = valueIterator.next().asIntegerValue().asByte();
    }
    return deserializedArray;
  }

  private short[] deserializeArrayShort(ArrayValue arrayValue) {
    short[] deserializedArray = new short[arrayValue.size()];
    int idx = 0;
    final Iterator valueIterator = arrayValue.iterator();
    while (valueIterator.hasNext()) {
      deserializedArray[idx++] = valueIterator.next().asIntegerValue().asShort();
    }
    return deserializedArray;
  }

  private int[] deserializeArrayInt(ArrayValue arrayValue) {
    int[] deserializedArray = new int[arrayValue.size()];
    int idx = 0;
    final Iterator valueIterator = arrayValue.iterator();
    while (valueIterator.hasNext()) {
      deserializedArray[idx++] = valueIterator.next().asIntegerValue().asInt();
    }
    return deserializedArray;
  }

  private long[] deserializeArrayLong(ArrayValue arrayValue) {
    long[] deserializedArray = new long[arrayValue.size()];
    int idx = 0;
    final Iterator valueIterator = arrayValue.iterator();
    while (valueIterator.hasNext()) {
      deserializedArray[idx++] = valueIterator.next().asIntegerValue().asLong();
    }
    return deserializedArray;
  }

  private float[] deserializeArrayFloat(ArrayValue arrayValue) {
    float[] deserializedArray = new float[arrayValue.size()];
    int idx = 0;
    final Iterator valueIterator = arrayValue.iterator();
    while (valueIterator.hasNext()) {
      deserializedArray[idx++] = valueIterator.next().asFloatValue().toFloat();
    }
    return deserializedArray;
  }

  private double[] deserializeArrayDouble(ArrayValue arrayValue) {
    double[] deserializedArray = new double[arrayValue.size()];
    int idx = 0;
    final Iterator valueIterator = arrayValue.iterator();
    while (valueIterator.hasNext()) {
      deserializedArray[idx++] = valueIterator.next().asFloatValue().toDouble();
    }
    return deserializedArray;
  }

  private char[] deserializeArrayChar(ArrayValue arrayValue) {
    char[] deserializedArray = new char[arrayValue.size()];
    int idx = 0;
    final Iterator valueIterator = arrayValue.iterator();
    while (valueIterator.hasNext()) {
      deserializedArray[idx++] = (char) valueIterator.next().asIntegerValue().asInt();
    }
    return deserializedArray;
  }

  private boolean[] deserializeArrayBoolean(ArrayValue arrayValue) {
    boolean[] deserializedArray = new boolean[arrayValue.size()];
    int idx = 0;
    final Iterator valueIterator = arrayValue.iterator();
    while (valueIterator.hasNext()) {
      deserializedArray[idx++] = valueIterator.next().asBooleanValue().getBoolean();
    }
    return deserializedArray;
  }

  private Object[] deserializeArrayObject(ArrayValue arrayValue) {
    Object[] deserializedArray = new Object[arrayValue.size()];
    int idx = 0;
    final Iterator valueIterator = arrayValue.iterator();
    while (valueIterator.hasNext()) {
      deserializedArray[idx++] = unpackValue(valueIterator.next().asArrayValue());
    }
    return deserializedArray;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy