view src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/IndexJungleTreeEditor.java @ 152:8a0aa8fc137c

Merge with a2c374a2686b82b0ad30f520412e191b84288fa9
author one
date Sat, 22 Nov 2014 15:25:09 +0900
parents d9fbddf77bf6 a2c374a2686b
children
line wrap: on
line source

package jp.ac.u_ryukyu.ie.cr.shoshi.jungle.transaction;

import java.nio.ByteBuffer;
import java.util.Iterator;

import fj.P2;
import fj.data.TreeMap;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.JungleTreeEditor;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.NodePath;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.IndexTreeEditor;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.TreeNode;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.logger.DefaultTreeOperationLog;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.logger.LoggingNode;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.logger.OperationLog;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.logger.TreeOperationLog;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.operations.DefaultTreeOperation;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.operations.NodeOperation;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.operations.TreeOperation;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.trasnformer.AppendChildAt;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.trasnformer.DeleteAttribute;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.trasnformer.DeleteChildAt;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.trasnformer.NodeEditor;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.trasnformer.PutAttribute;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.DefaultEither;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Either;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Error;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.IterableConverter;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Pair;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.TreeMapOrd;
import jp.ac.u_ryukyu.ie.cr.tatsuki.jungle.store.index.DefaultIndexEditor;
import jp.ac.u_ryukyu.ie.cr.tatsuki.jungle.store.index.DeleteChildIndexEditor;
import jp.ac.u_ryukyu.ie.cr.tatsuki.jungle.store.index.Index;
import jp.ac.u_ryukyu.ie.cr.tatsuki.jungle.store.index.IndexEditor;
import jp.ac.u_ryukyu.ie.cr.tatsuki.jungle.store.index.ParentIndex;

public class IndexJungleTreeEditor implements JungleTreeEditor {
  private final TransactionManager txManager;
  private final TreeNode root;
  private final TreeNode oldRoot;
  private final IndexTreeEditor editor;
  private final TreeOperationLog log;
  private final TreeOperationLog tmpLog;
  private Index index;
  private ParentIndex parentIndex;

  public Index getIndex() {
    return index;
  }

  public IndexJungleTreeEditor(TreeNode _root, TreeNode oldRoot, TransactionManager _txManager,
      IndexTreeEditor treeEditor, Index index, ParentIndex parentIndex) {
    this(_root, oldRoot, _txManager, treeEditor, new DefaultTreeOperationLog(), new DefaultTreeOperationLog(), index,
        parentIndex);
  }

  public IndexJungleTreeEditor(TreeNode _root, TreeNode oldRoot, TransactionManager _txManager,
      IndexTreeEditor treeEditor, TreeOperationLog log, Index index, ParentIndex parentIndex) {
    this(_root, oldRoot, _txManager, treeEditor, log, new DefaultTreeOperationLog(), index, parentIndex);
  }

  public IndexJungleTreeEditor(TreeNode newNode, TreeNode oldRoot, TransactionManager _txManager,
      IndexTreeEditor _editor, TreeOperationLog _log, TreeOperationLog tmpLog, Index index, ParentIndex parentIndex) {
    this.root = newNode;
    this.oldRoot = oldRoot;
    this.txManager = _txManager;
    this.editor = _editor;
    this.log = _log;
    this.index = index;
    this.parentIndex = parentIndex;
    this.tmpLog = tmpLog;
  }

  public Either<Error, IndexJungleTreeEditor> _edit(final NodePath _path, NodeEditor _e, IndexEditor indexEditor) {
    Either<Error, LoggingNode> either = editor.edit(root, _path, _e);
    if (either.isA()) {
      return DefaultEither.newA(either.a());
    }

    LoggingNode newLogging = either.b();
    OperationLog newLog = newLogging.getOperationLog();
    TreeNode newNode = newLogging.getWrap();

    IterableConverter.Converter<TreeOperation, NodeOperation> converter = new IterableConverter.Converter<TreeOperation, NodeOperation>() {
      @Override
      public TreeOperation conv(NodeOperation _b) {
        return new DefaultTreeOperation(_path, _b);
      }
    };

    Iterable<TreeOperation> iterable = new IterableConverter<TreeOperation, NodeOperation>(newLog, converter);
    DefaultTreeOperationLog treeOperationLog = new DefaultTreeOperationLog(iterable, newLog.length());
    TreeOperationLog newTmpLog = tmpLog.append(treeOperationLog);
    IndexJungleTreeEditor newIndexTreeEditor = new IndexJungleTreeEditor(newNode, oldRoot, txManager, this.editor, log,
        newTmpLog, index, parentIndex);
    return DefaultEither.newB(newIndexTreeEditor);
  }

  @Override
  public Either<Error, JungleTreeEditor> addNewChildAt(NodePath _path, int _pos) {
    AppendChildAt appendChildAt = new AppendChildAt(_pos);
    IndexEditor indexEditor = new DefaultIndexEditor(index);
    Either<Error, IndexJungleTreeEditor> either = _edit(_path, appendChildAt, indexEditor);
    Either<Error, JungleTreeEditor> newEither = DefaultEither.newB(either.b());
    return newEither;
  }

  @Override
  public Either<Error, JungleTreeEditor> deleteChildAt(NodePath _path, int _pos) {
    DeleteChildAt deleteChildAt = new DeleteChildAt(_pos);
    DeleteChildIndexEditor indexEditor = new DeleteChildIndexEditor(_pos, index);
    Either<Error, IndexJungleTreeEditor> either = _edit(_path, deleteChildAt, indexEditor);
    JungleTreeEditor editor = either.b();
    Either<Error, JungleTreeEditor> newEither = DefaultEither.newB(editor);
    return newEither;
  }

  @Override
  public Either<Error, JungleTreeEditor> putAttribute(NodePath _path, String _key, ByteBuffer _value) {
    PutAttribute putAttribute = new PutAttribute(_key, _value);
    IndexEditor indexEditor = new DefaultIndexEditor(index);
    Either<Error, IndexJungleTreeEditor> either = _edit(_path, putAttribute, indexEditor);
    JungleTreeEditor editor = either.b();
    Either<Error, JungleTreeEditor> newEither = DefaultEither.newB(editor);
    return newEither;
  }

  @Override
  public Either<Error, JungleTreeEditor> deleteAttribute(NodePath _path, String _key) {
    DeleteAttribute deleteAttribute = new DeleteAttribute(_key);
    IndexEditor indexEditor = new DefaultIndexEditor(index);
    Either<Error, IndexJungleTreeEditor> either = _edit(_path, deleteAttribute, indexEditor);
    Either<Error, JungleTreeEditor> newEither = DefaultEither.newB(either.b());
    return newEither;
  }

  @Override
  public Either<Error, JungleTreeEditor> edit(NodePath _path, NodeEditor _editor) {
    IndexEditor indexEditor = new DefaultIndexEditor(index);
    Either<Error, IndexJungleTreeEditor> either = _edit(_path, _editor, indexEditor);
    JungleTreeEditor editor = either.b();
    Either<Error, JungleTreeEditor> newEither = DefaultEither.newB(editor);
    return newEither;
  }

  @Override
  public Either<Error, JungleTreeEditor> success() {
    Pair<ParentIndex, Index> newIndexPair = editIndex(tmpLog);
    ParentIndex newParentIndex = newIndexPair.left();
    Index newIndex = newIndexPair.right();
    TreeOperationLog newLog = log.append(tmpLog);
    Either<Error, TransactionManager> either = txManager.commit(root, newLog, newIndex, newParentIndex);
    if (either.isA()) {
      return DefaultEither.newA(either.a());
    }

    TransactionManager newTxManager = either.b();
    JungleTreeEditor newTreeEditor = new IndexJungleTreeEditor(root, root, newTxManager, editor, index, parentIndex);

    return DefaultEither.newB(newTreeEditor);
  }

  private Pair<ParentIndex, Index> editIndex(TreeOperationLog tmpLog) {
    TreeMap<TreeNode, TreeNode> putParentNodeMap = TreeMap.empty(TreeMapOrd.treeNodeOrd);
    TreeMap<TreeNode, TreeNode> deleteParentNodeMap = TreeMap.empty(TreeMapOrd.treeNodeOrd);

    for (TreeOperation log : tmpLog) {

      NodePath targetNodePath = log.getNodePath();
      putParentNodeMap = getTargetNode(TreeMap.empty(TreeMapOrd.treeNodeOrd), root, targetNodePath);
      deleteParentNodeMap = getTargetNode(TreeMap.empty(TreeMapOrd.treeNodeOrd), oldRoot, targetNodePath);
      System.out.println(log.getNodePath().toString());
    }

    Pair<ParentIndex, Index> indexPair = new Pair<ParentIndex, Index>(parentIndex, index);
    if (!deleteParentNodeMap.isEmpty())
      indexPair = deleteIndexAttribute(putParentNodeMap, indexPair);

    if (!putParentNodeMap.isEmpty())
      indexPair = putIndexAttribute(putParentNodeMap, indexPair);

    ParentIndex newParentIndex = indexPair.left();
    Index newIndex = indexPair.right();
    Pair<ParentIndex, Index> newIndexPair = new Pair<ParentIndex, Index>(newParentIndex, newIndex);
    return newIndexPair;
  }

  private Pair<ParentIndex, Index> deleteIndexAttribute(TreeMap<TreeNode, TreeNode> deleteParentNodeMap,
      Pair<ParentIndex, Index> indexPair) {
    
    Iterator<P2<TreeNode, TreeNode>> parentNodeIterator = deleteParentNodeMap.iterator();
    ParentIndex newParentIndex = indexPair.left();
    Index newIndex = indexPair.right();

    for (; parentNodeIterator.hasNext();) {
      TreeNode parentNode = parentNodeIterator.next()._1();
      newIndex = newIndex.deleteNodeAll(parentNode);
      newParentIndex = newParentIndex.deleteAllChildren(parentNode);
    }
 
    Pair<ParentIndex, Index> newIndexPair = new Pair<ParentIndex, Index>(newParentIndex, newIndex);
    return newIndexPair;
  }

  private Pair<ParentIndex, Index> putIndexAttribute(TreeMap<TreeNode, TreeNode> putParentNodeMap,
      Pair<ParentIndex, Index> indexPair) {
    Iterator<P2<TreeNode, TreeNode>> parentNodeIterator = putParentNodeMap.iterator();
    ParentIndex newParentIndex = indexPair.left();
    Index newIndex = indexPair.right();

    for (; parentNodeIterator.hasNext();) {
      
      TreeNode parentNode = parentNodeIterator.next()._1();
      newIndex = newIndex.putNodeAll(parentNode);
      newParentIndex = newParentIndex.addAllChildren(parentNode);
     
    }
    Pair<ParentIndex, Index> newIndexPair = new Pair<ParentIndex, Index>(newParentIndex, newIndex);
    return newIndexPair;
  }

  private TreeMap<TreeNode, TreeNode> getTargetNode(TreeMap<TreeNode, TreeNode> treeNodeMap, TreeNode node,
      NodePath path) {
    if (path.size() == 0)
      return treeNodeMap;

    Pair<Integer, NodePath> pathNode = path.pop();

    if (pathNode.left() == -1) {
      TreeMap<TreeNode, TreeNode> newTreeNodeMap = treeNodeMap.set(node, node);
      return getTargetNode(newTreeNodeMap, node, pathNode.right());
    }

    Either<Error, TreeNode> either = node.getChildren().at(pathNode.left());
    if (either.isA())
      return treeNodeMap;

    TreeNode child = either.b();
    TreeMap<TreeNode, TreeNode> newTreeNodeMap = treeNodeMap.set(child, child);
    if (pathNode.right().size() == 0)
      return newTreeNodeMap;

    return getTargetNode(newTreeNodeMap, child, pathNode.right());

  }

  @Override
  public String getID() {
    return txManager.getUUID();
  }

  @Override
  public String getRevision() {
    return Long.toString(txManager.getRevision());
  }

  @Override
  public TreeNode getRoot() {
    return root;
  }

}