/** * Replication Benchmarker * https://github.com/score-team/replication-benchmarker/ * Copyright (C) 2013 LORIA / Inria / SCORE Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package jbenchmarker.rga; import jbenchmarker.core.Document; import jbenchmarker.core.SequenceOperation; import java.util.HashMap; import java.util.NoSuchElementException; import crdt.Operation; /** * * @author Roh */ public class RGADocument<T> implements Document { private HashMap<RGAS4Vector, RGANode<T>> hash; private RGANode head; private int size = 0; //private RGAPurger purger; public RGADocument() { super(); head = new RGANode(); hash = new HashMap<RGAS4Vector, RGANode<T>>(); //purger= new RGAPurger(this); } @Override public String view() { StringBuilder s = new StringBuilder(); RGANode node = head.getNext(); while (node != null) { if (node.isVisible()) { s.append(node.getContent()); } node = node.getNext(); } return s.toString(); } public void apply(Operation op) { RGAOperation rgaop = (RGAOperation) op; if (rgaop.getType() == SequenceOperation.OpType.delete) { RemoteDelete(rgaop); } else { RemoteInsert(rgaop); } } private void LocalInsert(RGAOperation op) { RGANode newnd = new RGANode(op.getS4VTms(), op.getContent()); if (op.getIntPos() == 0) { newnd.setNext(head.getNext()); head.setNext(newnd); } else { RGANode target = getVisibleNode(op.getIntPos()); if (target == null) { throw new NoSuchElementException("Don't find " + op.getIntPos()); } newnd.setNext(target.getNext()); target.setNext(newnd); } hash.put(op.getS4VTms(), newnd); ++size; } private void LocalDelete(RGAOperation op) { RGANode node = getVisibleNode(op.getIntPos()); if (node == null) { throw new NoSuchElementException("Don't find " + op.getIntPos()); } if (node.isVisible()) { --size; } node.makeTombstone(op.getS4VTms()); // purger.enrol(node); } private void RemoteInsert(RGAOperation op) { RGANode newnd = new RGANode(op.getS4VTms(), op.getContent()); RGANode prev, next; RGAS4Vector s4v = op.getS4VTms(); if (op.getS4VPos() == null) { prev = head; } else { prev = hash.get(op.getS4VPos()); } if (prev == null) { throw new NoSuchElementException("RemoteInsert"); } next = prev.getNext(); while (next != null) { if (s4v.compareTo(next.getKey()) == RGAS4Vector.AFTER) { break; } prev = next; next = next.getNext(); } newnd.setNext(next); prev.setNext(newnd); hash.put(op.getS4VTms(), newnd); ++size; } private void RemoteDelete(RGAOperation op) { RGANode node = hash.get(op.getS4VPos()); if (node == null) { throw new NoSuchElementException("Cannot find" + op.getS4VPos()); } if (node.isVisible()) { --size; } node.makeTombstone(op.getS4VTms()); // purger.enrol(node); } public RGAS4Vector getVisibleS4V(int v) { RGANode node = getVisibleNode(v); if (node == null) { throw new NoSuchElementException("getVisibleS4V"); } return node.getKey(); } public RGANode getVisibleNode(int v) { RGANode node = head; int j = 0; while (j < v && node != null) { node = node.getNext(); if (node != null && node.isVisible()) { j++; } } if (node == null || !node.isVisible()) { throw new NoSuchElementException("getVisibleNode"); } return node; } @Override public int viewLength() { return size; } }