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

org.sirix.node.NodeKind Maven / Gradle / Ivy

/**
 * Copyright (c) 2011, University of Konstanz, Distributed Systems Group All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted
 * provided that the following conditions are met: * Redistributions of source code must retain the
 * above copyright notice, this list of conditions and the following disclaimer. * Redistributions
 * in binary form must reproduce the above copyright notice, this list of conditions and the
 * following disclaimer in the documentation and/or other materials provided with the distribution.
 * * Neither the name of the University of Konstanz nor the names of its contributors may be used to
 * endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL  BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.sirix.node;

import static org.sirix.node.Utils.getVarLong;
import static org.sirix.node.Utils.putVarLong;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nonnegative;
import org.brackit.xquery.atomic.Atomic;
import org.brackit.xquery.atomic.QNm;
import org.brackit.xquery.module.Namespaces;
import org.brackit.xquery.xdm.Type;
import org.sirix.access.ResourceConfiguration;
import org.sirix.access.trx.node.HashType;
import org.sirix.api.PageReadOnlyTrx;
import org.sirix.index.AtomicUtil;
import org.sirix.index.avltree.AVLNode;
import org.sirix.index.avltree.keyvalue.CASValue;
import org.sirix.index.avltree.keyvalue.NodeReferences;
import org.sirix.index.path.summary.PathNode;
import org.sirix.node.delegates.NameNodeDelegate;
import org.sirix.node.delegates.NodeDelegate;
import org.sirix.node.delegates.StructNodeDelegate;
import org.sirix.node.delegates.ValueNodeDelegate;
import org.sirix.node.interfaces.NodePersistenter;
import org.sirix.node.interfaces.Record;
import org.sirix.node.json.ArrayNode;
import org.sirix.node.json.BooleanNode;
import org.sirix.node.json.JsonDocumentRootNode;
import org.sirix.node.json.NullNode;
import org.sirix.node.json.NumberNode;
import org.sirix.node.json.ObjectKeyNode;
import org.sirix.node.json.ObjectNode;
import org.sirix.node.json.StringNode;
import org.sirix.node.xml.AttributeNode;
import org.sirix.node.xml.CommentNode;
import org.sirix.node.xml.ElementNode;
import org.sirix.node.xml.NamespaceNode;
import org.sirix.node.xml.PINode;
import org.sirix.node.xml.TextNode;
import org.sirix.node.xml.XmlDocumentRootNode;
import org.sirix.page.UnorderedKeyValuePage;
import org.sirix.service.xml.xpath.AtomicValue;
import org.sirix.settings.Constants;
import org.sirix.settings.Fixed;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.hash.HashFunction;

/**
 * Enumeration for different nodes. All nodes are determined by a unique id.
 *
 * @author Sebastian Graf, University of Konstanz
 * @author Johannes Lichtenberger, University of Konstanz
 *
 */
public enum NodeKind implements NodePersistenter {

  /** Node kind is element. */
  ELEMENT((byte) 1, ElementNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final BigInteger hashCode = getHash(source, pageReadTrx);

      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegate(source, recordID, deweyID, pageReadTrx);

      // Struct delegate.
      final StructNodeDelegate structDel = deserializeStructDel(nodeDel, source);

      // Name delegate.
      final NameNodeDelegate nameDel = deserializeNameDelegate(nodeDel, source);

      // Attributes.
      final int attrCount = source.readInt();
      final List attrKeys = new ArrayList<>(attrCount);
      final BiMap attrs = HashBiMap.create();
      for (int i = 0; i < attrCount; i++) {
        final long nodeKey = source.readLong();
        attrKeys.add(nodeKey);
        attrs.put(source.readLong(), nodeKey);
      }

      // Namespaces.
      final int nsCount = source.readInt();
      final List namespKeys = new ArrayList<>(nsCount);
      for (int i = 0; i < nsCount; i++) {
        namespKeys.add(source.readLong());
      }

      final String uri = pageReadTrx.getName(nameDel.getURIKey(), NodeKind.NAMESPACE);
      final int prefixKey = nameDel.getPrefixKey();
      final String prefix = prefixKey == -1
          ? ""
          : pageReadTrx.getName(prefixKey, NodeKind.ELEMENT);
      final int localNameKey = nameDel.getLocalNameKey();
      final String localName = localNameKey == -1
          ? ""
          : pageReadTrx.getName(localNameKey, NodeKind.ELEMENT);

      return new ElementNode(hashCode, structDel, nameDel, attrKeys, attrs, namespKeys,
          new QNm(uri, prefix, localName));
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final ElementNode node = (ElementNode) record;
      if (pageReadTrx.getResourceManager().getResourceConfig().hashType != HashType.NONE)
        writeHash(sink, node.getHash());
      serializeDelegate(node.getNodeDelegate(), sink);
      serializeStructDelegate(node.getStructNodeDelegate(), sink);
      serializeNameDelegate(node.getNameNodeDelegate(), sink);
      sink.writeInt(node.getAttributeCount());
      for (int i = 0, attCount = node.getAttributeCount(); i < attCount; i++) {
        final long key = node.getAttributeKey(i);
        sink.writeLong(key);
        sink.writeLong(node.getAttributeNameKey(key).get());
      }
      sink.writeInt(node.getNamespaceCount());
      for (int i = 0, nspCount = node.getNamespaceCount(); i < nspCount; i++) {
        sink.writeLong(node.getNamespaceKey(i));
      }
    }
  },

  /** Node kind is attribute. */
  ATTRIBUTE((byte) 2, AttributeNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final BigInteger hashCode = getHash(source, pageReadTrx);

      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegate(source, recordID, deweyID, pageReadTrx);

      // Name delegate.
      final NameNodeDelegate nameDel = deserializeNameDelegate(nodeDel, source);

      // Val delegate.
      final boolean isCompressed = source.readByte() == (byte) 1
          ? true
          : false;
      final byte[] vals = new byte[source.readInt()];
      source.readFully(vals, 0, vals.length);
      final ValueNodeDelegate valDel = new ValueNodeDelegate(nodeDel, vals, isCompressed);

      final String uri = pageReadTrx.getName(nameDel.getURIKey(), NodeKind.NAMESPACE);
      final int prefixKey = nameDel.getPrefixKey();
      final String prefix = prefixKey == -1
          ? ""
          : pageReadTrx.getName(prefixKey, NodeKind.ATTRIBUTE);
      final int localNameKey = nameDel.getLocalNameKey();
      final String localName = localNameKey == -1
          ? ""
          : pageReadTrx.getName(localNameKey, NodeKind.ATTRIBUTE);

      final QNm name = new QNm(uri, prefix, localName);

      // Returning an instance.
      return new AttributeNode(hashCode, nodeDel, nameDel, valDel, name);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final AttributeNode node = (AttributeNode) record;
      if (pageReadTrx.getResourceManager().getResourceConfig().hashType != HashType.NONE)
        writeHash(sink, node.getHash());
      serializeDelegate(node.getNodeDelegate(), sink);
      serializeNameDelegate(node.getNameNodeDelegate(), sink);
      serializeValDelegate(node.getValNodeDelegate(), sink);
    }
  },

  /** Node kind is namespace. */
  NAMESPACE((byte) 13, NamespaceNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final BigInteger hashCode = getHash(source, pageReadTrx);

      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegate(source, recordID, deweyID, pageReadTrx);

      // Name delegate.
      final NameNodeDelegate nameDel = deserializeNameDelegate(nodeDel, source);

      final String uri = pageReadTrx.getName(nameDel.getURIKey(), NodeKind.NAMESPACE);
      final int prefixKey = nameDel.getPrefixKey();
      final String prefix = prefixKey == -1
          ? ""
          : pageReadTrx.getName(prefixKey, NodeKind.ELEMENT);
      final int localNameKey = nameDel.getLocalNameKey();
      final String localName = localNameKey == -1
          ? ""
          : pageReadTrx.getName(localNameKey, NodeKind.ELEMENT);

      final QNm name = new QNm(uri, prefix, localName);

      return new NamespaceNode(hashCode, nodeDel, nameDel, name);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final NamespaceNode node = (NamespaceNode) record;
      if (pageReadTrx.getResourceManager().getResourceConfig().hashType != HashType.NONE)
        writeHash(sink, node.getHash());
      serializeDelegate(node.getNodeDelegate(), sink);
      serializeNameDelegate(node.getNameNodeDelegate(), sink);
    }
  },

  /** Node kind is text. */
  TEXT((byte) 3, TextNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final BigInteger hashCode = getHash(source, pageReadTrx);

      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegate(source, recordID, deweyID, pageReadTrx);

      // Val delegate.
      final boolean isCompressed = source.readByte() == (byte) 1
          ? true
          : false;
      final byte[] vals = new byte[source.readInt()];
      source.readFully(vals, 0, vals.length);
      final ValueNodeDelegate valDel = new ValueNodeDelegate(nodeDel, vals, isCompressed);

      // Struct delegate.
      final long nodeKey = nodeDel.getNodeKey();
      final StructNodeDelegate structDel = new StructNodeDelegate(nodeDel, Fixed.NULL_NODE_KEY.getStandardProperty(),
          nodeKey - getVarLong(source), nodeKey - getVarLong(source), 0L, 0L);

      // Returning an instance.
      return new TextNode(hashCode, valDel, structDel);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final TextNode node = (TextNode) record;
      if (pageReadTrx.getResourceManager().getResourceConfig().hashType != HashType.NONE)
        writeHash(sink, node.getHash());
      serializeDelegate(node.getNodeDelegate(), sink);
      serializeValDelegate(node.getValNodeDelegate(), sink);
      final StructNodeDelegate del = node.getStructNodeDelegate();
      final long nodeKey = node.getNodeKey();
      putVarLong(sink, nodeKey - del.getRightSiblingKey());
      putVarLong(sink, nodeKey - del.getLeftSiblingKey());
    }
  },

  /** Node kind is processing instruction. */
  PROCESSING_INSTRUCTION((byte) 7, PINode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final BigInteger hashCode = getHash(source, pageReadTrx);

      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegate(source, recordID, deweyID, pageReadTrx);

      // Struct delegate.
      final StructNodeDelegate structDel = deserializeStructDel(nodeDel, source);

      // Name delegate.
      final NameNodeDelegate nameDel = deserializeNameDelegate(nodeDel, source);

      // Val delegate.
      final boolean isCompressed = source.readByte() == (byte) 1
          ? true
          : false;
      final byte[] vals = new byte[source.readInt()];
      source.readFully(vals, 0, vals.length);
      final ValueNodeDelegate valDel = new ValueNodeDelegate(nodeDel, vals, isCompressed);

      // Returning an instance.
      return new PINode(hashCode, structDel, nameDel, valDel, pageReadTrx);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final PINode node = (PINode) record;
      if (pageReadTrx.getResourceManager().getResourceConfig().hashType != HashType.NONE)
        writeHash(sink, node.getHash());
      serializeDelegate(node.getNodeDelegate(), sink);
      serializeStructDelegate(node.getStructNodeDelegate(), sink);
      serializeNameDelegate(node.getNameNodeDelegate(), sink);
      serializeValDelegate(node.getValNodeDelegate(), sink);
    }
  },

  /** Node kind is comment. */
  COMMENT((byte) 8, CommentNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final BigInteger hashCode = getHash(source, pageReadTrx);

      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegate(source, recordID, deweyID, pageReadTrx);

      // Val delegate.
      final boolean isCompressed = source.readByte() == (byte) 1
          ? true
          : false;
      final byte[] vals = new byte[source.readInt()];
      source.readFully(vals, 0, vals.length);
      final ValueNodeDelegate valDel = new ValueNodeDelegate(nodeDel, vals, isCompressed);

      // Struct delegate.
      final long nodeKey = nodeDel.getNodeKey();
      final StructNodeDelegate structDel = new StructNodeDelegate(nodeDel, Fixed.NULL_NODE_KEY.getStandardProperty(),
          nodeKey - getVarLong(source), nodeKey - getVarLong(source), 0L, 0L);

      // Returning an instance.
      return new CommentNode(hashCode, valDel, structDel);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final CommentNode node = (CommentNode) record;
      if (pageReadTrx.getResourceManager().getResourceConfig().hashType != HashType.NONE)
        writeHash(sink, node.getHash());
      serializeDelegate(node.getNodeDelegate(), sink);
      serializeValDelegate(node.getValNodeDelegate(), sink);
      final StructNodeDelegate del = node.getStructNodeDelegate();
      final long nodeKey = node.getNodeKey();
      putVarLong(sink, nodeKey - del.getRightSiblingKey());
      putVarLong(sink, nodeKey - del.getLeftSiblingKey());
    }
  },

  /** Node kind is document root. */
  // Virtualize document root node?
  XDM_DOCUMENT((byte) 9, XmlDocumentRootNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final HashFunction hashFunction = pageReadTrx.getResourceManager().getResourceConfig().nodeHashFunction;

      final NodeDelegate nodeDel = new NodeDelegate(Fixed.DOCUMENT_NODE_KEY.getStandardProperty(),
          Fixed.NULL_NODE_KEY.getStandardProperty(), hashFunction, null, getVarLong(source), SirixDeweyID.newRootID());
      final StructNodeDelegate structDel =
          new StructNodeDelegate(nodeDel, getVarLong(source), Fixed.NULL_NODE_KEY.getStandardProperty(),
              Fixed.NULL_NODE_KEY.getStandardProperty(), source.readByte() == ((byte) 0)
                  ? 0
                  : 1,
              source.readLong());
      return new XmlDocumentRootNode(nodeDel, structDel);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final XmlDocumentRootNode node = (XmlDocumentRootNode) record;
      // writeHash(sink, node.getHash());
      putVarLong(sink, node.getRevision());
      putVarLong(sink, node.getFirstChildKey());
      sink.writeByte(node.hasFirstChild()
          ? (byte) 1
          : (byte) 0);
      sink.writeLong(node.getDescendantCount());
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      return null;
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {}
  },

  /** Whitespace text. */
  WHITESPACE((byte) 4, null) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx) {
      throw new UnsupportedOperationException();
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      return null;
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {}
  },

  /** Node kind is deleted node. */
  DELETE((byte) 5, DeletedNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) {
      final HashFunction hashFunction = pageReadTrx.getResourceManager().getResourceConfig().nodeHashFunction;
      final NodeDelegate delegate = new NodeDelegate(recordID, 0, hashFunction, null, 0, null);
      return new DeletedNode(delegate);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx) {}

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      return Optional.empty();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {}
  },

  /** NullNode to support the Null Object pattern. */
  NULL((byte) 6, NullNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serialize(final DataOutput ink, final Record record, final PageReadOnlyTrx pageReadTrx) {
      throw new UnsupportedOperationException();
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      return null;
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {}
  },

  /** Dumb node for testing. */
  DUMB((byte) 20, DumbNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) {
      return new DumbNode(recordID);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx) {
      throw new UnsupportedOperationException();
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }
  },

  /** AtomicKind. */
  ATOMIC((byte) 15, AtomicValue.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx) {
      throw new UnsupportedOperationException();
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }
  },

  /** Node kind is path node. */
  PATH((byte) 16, PathNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegateWithoutIDs(source, recordID, pageReadTrx);

      // Struct delegate.
      final StructNodeDelegate structDel = deserializeStructDel(nodeDel, source);

      // Name delegate.
      final NameNodeDelegate nameDel = deserializeNameDelegate(nodeDel, source);

      return new PathNode(nodeDel, structDel, nameDel, NodeKind.getKind(source.readByte()), source.readInt(),
          source.readInt());
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final PathNode node = (PathNode) record;
      serializeDelegate(node.getNodeDelegate(), sink);
      serializeStructDelegate(node.getStructNodeDelegate(), sink);
      serializeNameDelegate(node.getNameNodeDelegate(), sink);
      sink.writeByte(node.getPathKind().getId());
      sink.writeInt(node.getReferences());
      sink.writeInt(node.getLevel());
    };

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }
  },

  /** Node kind is a CAS-AVL node. */
  CASAVL((byte) 17, AVLNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final int valueSize = source.readInt();
      final byte[] value = new byte[valueSize];
      source.readFully(value, 0, valueSize);
      final int typeSize = source.readInt();
      final byte[] type = new byte[typeSize];
      source.readFully(type, 0, typeSize);
      final int keySize = source.readInt();
      final Set nodeKeys = new HashSet<>(keySize);
      long key = getVarLong(source);
      nodeKeys.add(key);
      for (int i = 1; i < keySize; i++) {
        if (i + 1 < keySize) {
          key += getVarLong(source);
          nodeKeys.add(key);
        }
      }
      final Type atomicType = resolveType(new String(type, Constants.DEFAULT_ENCODING));

      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegateWithoutIDs(source, recordID, pageReadTrx);
      final long leftChild = getVarLong(source);
      final long rightChild = getVarLong(source);
      final long pathNodeKey = getVarLong(source);
      final boolean isChanged = source.readBoolean();

      final Atomic atomic = AtomicUtil.fromBytes(value, atomicType);
      AVLNode node;
      node = new AVLNode(new CASValue(atomic, atomicType, pathNodeKey),
          new NodeReferences(nodeKeys), nodeDel);

      node.setLeftChildKey(leftChild);
      node.setRightChildKey(rightChild);
      node.setChanged(isChanged);
      return node;
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      @SuppressWarnings("unchecked")
      final AVLNode node = (AVLNode) record;
      final CASValue key = node.getKey();
      final byte[] textValue = key.getValue();
      sink.writeInt(textValue.length);
      sink.write(textValue);
      final byte[] type = key.getType().toString().getBytes(Constants.DEFAULT_ENCODING);
      sink.writeInt(type.length);
      sink.write(type);
      final NodeReferences value = node.getValue();
      final Set nodeKeys = value.getNodeKeys();

      // Store in a list and sort the list.
      final List listNodeKeys = new ArrayList<>(nodeKeys);
      Collections.sort(listNodeKeys);
      sink.writeInt(listNodeKeys.size());
      putVarLong(sink, listNodeKeys.get(0));
      for (int i = 0; i < listNodeKeys.size(); i++) {
        if (i + 1 < listNodeKeys.size()) {
          final long diff = listNodeKeys.get(i + 1) - listNodeKeys.get(i);
          putVarLong(sink, diff);
        }
      }
      serializeDelegate(node.getNodeDelegate(), sink);
      putVarLong(sink, node.getLeftChildKey());
      putVarLong(sink, node.getRightChildKey());
      putVarLong(sink, key.getPathNodeKey());
      sink.writeBoolean(node.isChanged());
    };

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    private Type resolveType(final String s) {
      final QNm name =
          new QNm(Namespaces.XS_NSURI, Namespaces.XS_PREFIX, s.substring(Namespaces.XS_PREFIX.length() + 1));
      for (final Type type : Type.builtInTypes) {
        if (type.getName().getLocalName().equals(name.getLocalName())) {
          return type;
        }
      }
      throw new IllegalStateException("Unknown content type: " + name);
    }
  },

  /** Node kind is a PATH-AVL node. */
  PATHAVL((byte) 18, AVLNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final long key = getVarLong(source);
      final int keySize = source.readInt();
      final Set nodeKeys = new HashSet<>(keySize);
      for (int i = 0; i < keySize; i++) {
        nodeKeys.add(source.readLong());
      }
      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegateWithoutIDs(source, recordID, pageReadTrx);
      final long leftChild = getVarLong(source);
      final long rightChild = getVarLong(source);
      final boolean isChanged = source.readBoolean();
      final AVLNode node = new AVLNode<>(key, new NodeReferences(nodeKeys), nodeDel);
      node.setLeftChildKey(leftChild);
      node.setRightChildKey(rightChild);
      node.setChanged(isChanged);
      return node;
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      @SuppressWarnings("unchecked")
      final AVLNode node = (AVLNode) record;
      putVarLong(sink, node.getKey().longValue());
      final NodeReferences value = node.getValue();
      final Set nodeKeys = value.getNodeKeys();
      sink.writeInt(nodeKeys.size());
      for (final long nodeKey : nodeKeys) {
        sink.writeLong(nodeKey);
      }
      serializeDelegate(node.getNodeDelegate(), sink);
      putVarLong(sink, node.getLeftChildKey());
      putVarLong(sink, node.getRightChildKey());
      sink.writeBoolean(node.isChanged());
    };

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }
  },

  /** Node kind is a PATH-AVL node. */
  NAMEAVL((byte) 19, AVLNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final byte[] nspBytes = new byte[source.readInt()];
      source.readFully(nspBytes);
      final byte[] prefixBytes = new byte[source.readInt()];
      source.readFully(prefixBytes);
      final byte[] localNameBytes = new byte[source.readInt()];
      source.readFully(localNameBytes);
      final QNm name = new QNm(new String(nspBytes, Constants.DEFAULT_ENCODING),
          new String(prefixBytes, Constants.DEFAULT_ENCODING), new String(localNameBytes, Constants.DEFAULT_ENCODING));
      final int keySize = source.readInt();
      final Set nodeKeys = new HashSet<>(keySize);
      for (int i = 0; i < keySize; i++) {
        nodeKeys.add(source.readLong());
      }
      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegateWithoutIDs(source, recordID, pageReadTrx);
      final long leftChild = getVarLong(source);
      final long rightChild = getVarLong(source);
      final boolean isChanged = source.readBoolean();
      final AVLNode node = new AVLNode<>(name, new NodeReferences(nodeKeys), nodeDel);
      node.setLeftChildKey(leftChild);
      node.setRightChildKey(rightChild);
      node.setChanged(isChanged);
      return node;
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      @SuppressWarnings("unchecked")
      final AVLNode node = (AVLNode) record;
      final byte[] nspBytes = node.getKey().getNamespaceURI().getBytes();
      sink.writeInt(nspBytes.length);
      sink.write(nspBytes);
      final byte[] prefixBytes = node.getKey().getPrefix().getBytes();
      sink.writeInt(prefixBytes.length);
      sink.write(prefixBytes);
      final byte[] localNameBytes = node.getKey().getLocalName().getBytes();
      sink.writeInt(localNameBytes.length);
      sink.write(localNameBytes);
      final NodeReferences value = node.getValue();
      final Set nodeKeys = value.getNodeKeys();
      sink.writeInt(nodeKeys.size());
      for (final long nodeKey : nodeKeys) {
        sink.writeLong(nodeKey);
      }
      serializeDelegate(node.getNodeDelegate(), sink);
      putVarLong(sink, node.getLeftChildKey());
      putVarLong(sink, node.getRightChildKey());
      sink.writeBoolean(node.isChanged());
    };

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }
  },

  /** Node includes a deweyID <=> nodeKey mapping. */
  DEWEYIDMAPPING((byte) 23, DeweyIDMappingNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx) {
      throw new UnsupportedOperationException();
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }
  },

  /** JSON object node. */
  OBJECT((byte) 24, ObjectNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final BigInteger hashCode = getHash(source, pageReadTrx);

      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegate(source, recordID, deweyID, pageReadTrx);

      // Struct delegate.
      final StructNodeDelegate structDel = deserializeStructDel(nodeDel, source);

      // Returning an instance.
      return new ObjectNode(hashCode, structDel);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final ObjectNode node = (ObjectNode) record;
      if (pageReadTrx.getResourceManager().getResourceConfig().hashType != HashType.NONE)
        writeHash(sink, node.getHash());
      serializeDelegate(node.getNodeDelegate(), sink);
      serializeStructDelegate(node.getStructNodeDelegate(), sink);
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }
  },

  /** JSON array node. */
  ARRAY((byte) 25, ArrayNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final BigInteger hashCode = getHash(source, pageReadTrx);

      final long pathNodeKey = source.readLong();

      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegate(source, recordID, deweyID, pageReadTrx);

      // Struct delegate.
      final StructNodeDelegate structDel = deserializeStructDel(nodeDel, source);

      // Returning an instance.
      return new ArrayNode(hashCode, structDel, pathNodeKey);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final ArrayNode node = (ArrayNode) record;
      if (pageReadTrx.getResourceManager().getResourceConfig().hashType != HashType.NONE)
        writeHash(sink, node.getHash());
      sink.writeLong(node.getPathNodeKey());
      serializeDelegate(node.getNodeDelegate(), sink);
      serializeStructDelegate(node.getStructNodeDelegate(), sink);
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }
  },

  /** JSON array node. */
  OBJECT_KEY((byte) 26, ObjectKeyNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final BigInteger hashCode = getHash(source, pageReadTrx);

      final int nameKey = source.readInt();
      final long pathNodeKey = getVarLong(source);

      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegate(source, recordID, deweyID, pageReadTrx);

      // Struct delegate.
      final StructNodeDelegate structDel = deserializeStructDel(nodeDel, source);

      final String name = nameKey == -1
          ? ""
          : pageReadTrx.getName(nameKey, NodeKind.OBJECT_KEY);

      // Returning an instance.
      return new ObjectKeyNode(hashCode, structDel, nameKey, name, pathNodeKey);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final ObjectKeyNode node = (ObjectKeyNode) record;
      if (pageReadTrx.getResourceManager().getResourceConfig().hashType != HashType.NONE)
        writeHash(sink, node.getHash());
      sink.writeInt(node.getNameKey());
      putVarLong(sink, node.getPathNodeKey());
      serializeDelegate(node.getNodeDelegate(), sink);
      serializeStructDelegate(node.getStructNodeDelegate(), sink);
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }
  },

  /** JSON string value node. */
  STRING_VALUE((byte) 30, StringNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final BigInteger hashCode = getHash(source, pageReadTrx);

      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegate(source, recordID, deweyID, pageReadTrx);

      // Val delegate.
      final boolean isCompressed = source.readByte() == (byte) 1
          ? true
          : false;
      final byte[] vals = new byte[source.readInt()];
      source.readFully(vals, 0, vals.length);
      final ValueNodeDelegate valDel = new ValueNodeDelegate(nodeDel, vals, isCompressed);

      // Struct delegate.
      final StructNodeDelegate structDel = deserializeStructDel(nodeDel, source);

      // Returning an instance.
      return new StringNode(hashCode, valDel, structDel);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final StringNode node = (StringNode) record;
      if (pageReadTrx.getResourceManager().getResourceConfig().hashType != HashType.NONE)
        writeHash(sink, node.getHash());
      serializeDelegate(node.getNodeDelegate(), sink);
      serializeValDelegate(node.getValNodeDelegate(), sink);
      serializeStructDelegate(node.getStructNodeDelegate(), sink);
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }
  },

  /** JSON boolean value node. */
  BOOLEAN_VALUE((byte) 27, BooleanNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final BigInteger hashCode = getHash(source, pageReadTrx);

      final boolean boolValue = source.readBoolean();
      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegate(source, recordID, deweyID, pageReadTrx);

      // Struct delegate.
      final StructNodeDelegate structDel = deserializeStructDel(nodeDel, source);

      // Returning an instance.
      return new BooleanNode(hashCode, boolValue, structDel);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final BooleanNode node = (BooleanNode) record;
      if (pageReadTrx.getResourceManager().getResourceConfig().hashType != HashType.NONE)
        writeHash(sink, node.getHash());
      sink.writeBoolean(node.getValue());
      serializeDelegate(node.getNodeDelegate(), sink);
      serializeStructDelegate(node.getStructNodeDelegate(), sink);
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }
  },

  /** JSON number value node. */
  NUMBER_VALUE((byte) 28, NumberNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final BigInteger hashCode = getHash(source, pageReadTrx);
      final byte valueType = source.readByte();
      final Number number;

      switch (valueType) {
        case 0:
          number = source.readDouble();
          break;
        case 1:
          number = source.readFloat();
          break;
        case 2:
          number = source.readInt();
          break;
        case 3:
          number = source.readLong();
          break;
        case 4:
          number = deserializeBigInteger(source);
          break;
        case 5:
          final BigInteger bigInt = deserializeBigInteger(source);
          final int scale = source.readInt();
          number = new BigDecimal(bigInt, scale);
          break;
        default:
          throw new AssertionError("Type not known.");
      }

      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegate(source, recordID, deweyID, pageReadTrx);

      // Struct delegate.
      final StructNodeDelegate structDel = deserializeStructDel(nodeDel, source);

      // Returning an instance.
      return new NumberNode(hashCode, number, structDel);
    }

    private BigInteger deserializeBigInteger(final DataInput source) throws IOException {
      final byte[] bytes = new byte[source.readInt()];
      source.readFully(bytes);
      return new BigInteger(bytes);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final NumberNode node = (NumberNode) record;
      if (pageReadTrx.getResourceManager().getResourceConfig().hashType != HashType.NONE)
        writeHash(sink, node.getHash());
      final Number number = node.getValue();

      if (number instanceof Double) {
        sink.writeByte(0);
        sink.writeDouble(number.doubleValue());
      } else if (number instanceof Float) {
        sink.writeByte(1);
        sink.writeFloat(number.floatValue());
      } else if (number instanceof Integer) {
        sink.writeByte(2);
        sink.writeInt(number.intValue());
      } else if (number instanceof Long) {
        sink.writeByte(3);
        sink.writeLong(number.longValue());
      } else if (number instanceof BigInteger) {
        sink.writeByte(4);
        serializeBigInteger(sink, (BigInteger) number);
      } else if (number instanceof BigDecimal) {
        sink.writeByte(5);
        final BigDecimal value = (BigDecimal) number;
        final BigInteger bigInt = value.unscaledValue();
        final int scale = value.scale();
        serializeBigInteger(sink, bigInt);
        sink.writeInt(scale);
      } else {
        throw new AssertionError("Type not known.");
      }

      serializeDelegate(node.getNodeDelegate(), sink);
      serializeStructDelegate(node.getStructNodeDelegate(), sink);
    }

    private void serializeBigInteger(final DataOutput sink, final BigInteger bigInteger) throws IOException {
      final byte[] bytes = bigInteger.toByteArray();
      sink.writeInt(bytes.length);
      sink.write(bytes);
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }
  },
  /** JSON null node. */
  NULL_VALUE((byte) 29, NullNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      final BigInteger hashCode = getHash(source, pageReadTrx);

      // Node delegate.
      final NodeDelegate nodeDel = deserializeNodeDelegate(source, recordID, deweyID, pageReadTrx);

      // Struct delegate.
      final StructNodeDelegate structDel = deserializeStructDel(nodeDel, source);

      // Returning an instance.
      return new NullNode(hashCode, structDel);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final NullNode node = (NullNode) record;
      if (pageReadTrx.getResourceManager().getResourceConfig().hashType != HashType.NONE)
        writeHash(sink, node.getHash());
      serializeDelegate(node.getNodeDelegate(), sink);
      serializeStructDelegate(node.getStructNodeDelegate(), sink);
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }
  },
  /** Node kind is document root. */
  // Virtualize document root node?
  JSON_DOCUMENT((byte) 31, JsonDocumentRootNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {

      final HashFunction hashFunction = pageReadTrx.getResourceManager().getResourceConfig().nodeHashFunction;

      final NodeDelegate nodeDel = new NodeDelegate(Fixed.DOCUMENT_NODE_KEY.getStandardProperty(),
          Fixed.NULL_NODE_KEY.getStandardProperty(), hashFunction, null, getVarLong(source), null);
      final StructNodeDelegate structDel =
          new StructNodeDelegate(nodeDel, getVarLong(source), Fixed.NULL_NODE_KEY.getStandardProperty(),
              Fixed.NULL_NODE_KEY.getStandardProperty(), source.readByte() == ((byte) 0)
                  ? 0
                  : 1,
              source.readLong());
      return new JsonDocumentRootNode(nodeDel, structDel);
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final JsonDocumentRootNode node = (JsonDocumentRootNode) record;

      putVarLong(sink, node.getRevision());
      putVarLong(sink, node.getFirstChildKey());
      sink.writeByte(node.hasFirstChild()
          ? (byte) 1
          : (byte) 0);
      sink.writeLong(node.getDescendantCount());
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      return null;
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {}
  },

  HASH_ENTRY((byte) 32, HashEntryNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      return new HashEntryNode(getVarLong(source), source.readInt(), source.readUTF());
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final HashEntryNode node = (HashEntryNode) record;

      putVarLong(sink, node.getNodeKey());
      sink.writeInt(node.getKey());
      sink.writeUTF(node.getValue());
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      return null;
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {}
  },

  HASH_NAME_COUNT_TO_NAME_ENTRY((byte) 33, HashCountEntryNode.class) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      return new HashCountEntryNode(getVarLong(source), source.readInt());
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      final HashCountEntryNode node = (HashCountEntryNode) record;

      putVarLong(sink, node.getNodeKey());
      sink.writeInt(node.getValue());
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      return null;
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {}
  },

  /** Node type not known. */
  UNKNOWN((byte) 22, null) {
    @Override
    public Record deserialize(final DataInput source, final @Nonnegative long recordID, final SirixDeweyID deweyID,
        final PageReadOnlyTrx pageReadTrx) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serialize(final DataOutput sink, final Record record, final PageReadOnlyTrx pageReadTrx)
        throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID prevDeweyID,
        ResourceConfiguration resourceConfig) throws IOException {
      throw new UnsupportedOperationException();
    }
  };

  /** Identifier. */
  private final byte mId;

  /** Class. */
  private final Class mClass;

  /** Mapping of keys -> nodes. */
  private static final Map INSTANCEFORID = new HashMap<>();

  /** Mapping of class -> nodes. */
  private static final Map, NodeKind> INSTANCEFORCLASS = new HashMap<>();

  static {
    for (final NodeKind node : values()) {
      INSTANCEFORID.put(node.mId, node);
      INSTANCEFORCLASS.put(node.mClass, node);
    }
  }

  /**
   * Constructor.
   *
   * @param id unique identifier
   * @param clazz class
   */
  private NodeKind(final byte id, final Class clazz) {
    mId = id;
    mClass = clazz;
  }

  /**
   * Get the nodeKind.
   *
   * @return the unique kind
   */
  public byte getId() {
    return mId;
  }

  /**
   * Get class of node.
   *
   * @return class of node
   */
  public Class getNodeClass() {
    return mClass;
  }

  /**
   * Public method to get the related node based on the identifier.
   *
   * @param id the identifier for the node
   * @return the related node
   */
  public static NodeKind getKind(final byte id) {
    return INSTANCEFORID.get(id);
  }

  /**
   * Public method to get the related node based on the class.
   *
   * @param clazz the class for the node
   * @return the related node
   */
  public static NodeKind getKind(final Class clazz) {
    return INSTANCEFORCLASS.get(clazz);
  }

  @Override
  public Optional deserializeDeweyID(DataInput source, SirixDeweyID previousDeweyID,
      ResourceConfiguration resourceConfig) throws IOException {
    if (resourceConfig.areDeweyIDsStored) {
      if (previousDeweyID != null) {
        final byte[] previousDeweyIDBytes = previousDeweyID.toBytes();
        final int cutOffSize = source.readByte();
        final int size = source.readByte();
        final byte[] deweyIDBytes = new byte[size];
        source.readFully(deweyIDBytes);

        final byte[] bytes = new byte[cutOffSize + deweyIDBytes.length];
        final ByteBuffer target = ByteBuffer.wrap(bytes);
        target.put(Arrays.copyOfRange(previousDeweyIDBytes, 0, cutOffSize));
        target.put(deweyIDBytes);

        return Optional.of(new SirixDeweyID(bytes));
      } else {
        final byte deweyIDLength = source.readByte();
        final byte[] deweyIDBytes = new byte[deweyIDLength];
        source.readFully(deweyIDBytes, 0, deweyIDLength);
        return Optional.of(new SirixDeweyID(deweyIDBytes));
      }
    } else {
      return Optional.empty();
    }
  }

  @Override
  public void serializeDeweyID(DataOutput sink, NodeKind nodeKind, SirixDeweyID deweyID, SirixDeweyID nextDeweyID,
      ResourceConfiguration resourceConfig) throws IOException {
    if (resourceConfig.areDeweyIDsStored) {
      if (nextDeweyID != null) {
        final byte[] deweyIDBytes = deweyID.toBytes();
        final byte[] nextDeweyIDBytes = nextDeweyID.toBytes();

        assert deweyIDBytes.length <= nextDeweyIDBytes.length;

        int i = 0;
        for (; i < deweyIDBytes.length; i++) {
          if (deweyIDBytes[i] != nextDeweyIDBytes[i]) {
            break;
          }
        }
        writeDeweyID(sink, nextDeweyIDBytes, i);
      } else {
        final byte[] deweyIDBytes = deweyID.toBytes();
        sink.writeByte(deweyIDBytes.length);
        sink.write(deweyIDBytes);
      }
    }
  }

  private static final BigInteger getHash(final DataInput source, final PageReadOnlyTrx pageReadTrx)
      throws IOException {
    final BigInteger hashCode;
    if (pageReadTrx.getResourceManager().getResourceConfig().hashType == HashType.NONE)
      hashCode = null;
    else
      hashCode = readHash(source);
    return hashCode;
  }

  /**
   * Deserialize node delegate without stored dewey IDs.
   *
   * @param source source to read from
   * @param resourceConfig resource configuration
   * @return {@link NodeDelegate} instance
   */
  private static final NodeDelegate deserializeNodeDelegateWithoutIDs(final DataInput source,
      final @Nonnegative long recordID, final PageReadOnlyTrx pageReadTrx) throws IOException {
    final long nodeKey = recordID;
    final long parentKey = nodeKey - getVarLong(source);
    final long revision = getVarLong(source);
    final HashFunction hashFunction = pageReadTrx.getResourceManager().getResourceConfig().nodeHashFunction;
    return new NodeDelegate(nodeKey, parentKey, hashFunction, null, revision, null);
  }

  /**
   * Deserialize node delegate.
   *
   * @param source source to read from
   * @param resourceConfig resource configuration
   * @return {@link NodeDelegate} instance
   */
  private static final NodeDelegate deserializeNodeDelegate(final DataInput source, final @Nonnegative long recordID,
      final SirixDeweyID id, final PageReadOnlyTrx pageReadTrx) throws IOException {
    final long nodeKey = recordID;
    final long parentKey = nodeKey - getVarLong(source);
    final long revision = getVarLong(source);
    final HashFunction hashFunction = pageReadTrx.getResourceManager().getResourceConfig().nodeHashFunction;
    return new NodeDelegate(nodeKey, parentKey, hashFunction, null, revision, id);
  }

  /**
   * Serializing the {@link NodeDelegate} instance.
   *
   * @param nodeDel node delegate
   * @param nextNode next node in the page or {@code null}
   * @param sink to serialize to
   * @param pageReadTrx {@link PageReadOnlyTrx} instance
   * @param {@link ResourceConfiguration} instance
   */
  private static final void serializeDelegate(final NodeDelegate nodeDel, final DataOutput sink) throws IOException {
    putVarLong(sink, nodeDel.getNodeKey() - nodeDel.getParentKey());
    putVarLong(sink, nodeDel.getRevision());
  }

  /**
   * Write the deweyID.
   *
   * @param sink to write to
   * @param deweyID deweyID in bytes
   * @param i the index from which to start the copy of the array
   */
  private static void writeDeweyID(final DataOutput sink, final byte[] deweyID, final @Nonnegative int i)
      throws IOException {
    sink.writeByte(i);
    sink.writeByte(deweyID.length - i);
    sink.write(Arrays.copyOfRange(deweyID, i, deweyID.length));
  }

  /**
   * Serializing the {@link StructNodeDelegate} instance.
   *
   * @param nodeDel to be serialize
   * @param sink to serialize to
   */
  private static final void serializeStructDelegate(final StructNodeDelegate nodeDel, final DataOutput sink)
      throws IOException {
    putVarLong(sink, nodeDel.getNodeKey() - nodeDel.getRightSiblingKey());
    putVarLong(sink, nodeDel.getNodeKey() - nodeDel.getLeftSiblingKey());
    putVarLong(sink, nodeDel.getNodeKey() - nodeDel.getFirstChildKey());
    putVarLong(sink, nodeDel.getChildCount());
    putVarLong(sink, nodeDel.getDescendantCount() - nodeDel.getChildCount());
  }

  /**
   * Deserialize struct delegate.
   *
   * @param nodeDel node delegate
   * @param source input source
   * @return {@link StructNodeDelegate} instance
   */
  private static final StructNodeDelegate deserializeStructDel(final NodeDelegate nodeDel, final DataInput source)
      throws IOException {
    final long currKey = nodeDel.getNodeKey();
    final long rightSibl = currKey - getVarLong(source);
    final long leftSibl = currKey - getVarLong(source);
    final long firstChild = currKey - getVarLong(source);
    final long childCount = getVarLong(source);
    final long descendantCount = getVarLong(source) + childCount;
    return new StructNodeDelegate(nodeDel, firstChild, rightSibl, leftSibl, childCount, descendantCount);
  }

  /**
   * Deserialize name node delegate.
   *
   * @param nodeDel {@link NodeDelegate} instance
   * @param source source to read from
   * @return {@link NameNodeDelegate} instance
   */
  private static final NameNodeDelegate deserializeNameDelegate(final NodeDelegate nodeDel, final DataInput source)
      throws IOException {
    final int uriKey = source.readInt();
    int prefixKey = source.readInt();
    int localNameKey = source.readInt();
    return new NameNodeDelegate(nodeDel, uriKey, prefixKey, localNameKey, getVarLong(source));
  }

  /**
   * Serializing the {@link NameNodeDelegate} instance.
   *
   * @param nameDel {@link NameNodeDelegate} instance
   * @param sink to serialize to
   */
  private static final void serializeNameDelegate(final NameNodeDelegate nameDel, final DataOutput sink)
      throws IOException {
    sink.writeInt(nameDel.getURIKey());
    sink.writeInt(nameDel.getPrefixKey());
    sink.writeInt(nameDel.getLocalNameKey());
    putVarLong(sink, nameDel.getPathNodeKey());
  }

  /**
   * Serializing the {@link ValueNodeDelegate} instance.
   *
   * @param valueDel to be serialized
   * @param sink to serialize to
   */
  private static final void serializeValDelegate(final ValueNodeDelegate valueDel, final DataOutput sink)
      throws IOException {
    final boolean isCompressed = valueDel.isCompressed();
    sink.writeByte(isCompressed
        ? (byte) 1
        : (byte) 0);
    final byte[] value = isCompressed
        ? valueDel.getCompressed()
        : valueDel.getRawValue();
    sink.writeInt(value.length);
    sink.write(value);
  }

  private static BigInteger readHash(final DataInput source) throws IOException {
    final byte[] hashBytes = new byte[source.readByte()];
    source.readFully(hashBytes);
    return new BigInteger(1, hashBytes);
  }

  private static void writeHash(final DataOutput sink, final BigInteger hashCode) throws IOException {
    assert !BigInteger.ZERO.equals(hashCode);
    final byte[] bigIntegerBytes = hashCode.toByteArray();
    final List bytes = new ArrayList<>();
    final int maxLength = bigIntegerBytes.length < 17
        ? bigIntegerBytes.length
        : 17;

    for (int i = 1; i < maxLength; i++) {
      bytes.add(bigIntegerBytes[i]);
    }

    assert bytes.size() < 17;

    sink.writeByte(bigIntegerBytes.length);
    sink.write(bigIntegerBytes);
  }

  /**
   * Simple DumbNode just for testing the {@link UnorderedKeyValuePage}s.
   *
   * @author Sebastian Graf, University of Konstanz
   * @author Johannes Lichtenberger
   *
   */
  public static class DumbNode implements Record {

    /** Node key. */
    private final long mNodeKey;

    /**
     * Simple constructor.
     *
     * @param nodeKey to be set
     * @param pHash to be set
     */
    public DumbNode(final long nodeKey) {
      mNodeKey = nodeKey;
    }

    @Override
    public long getNodeKey() {
      return mNodeKey;
    }

    @Override
    public NodeKind getKind() {
      return NodeKind.NULL;
    }

    @Override
    public long getRevision() {
      return 0;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy