/** * 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 crdt.tree.fctree.policy; import crdt.tree.fctree.FCIdentifier; import crdt.tree.fctree.FCNode; import crdt.tree.fctree.FCNodeGf; import crdt.tree.fctree.FCPosition; import crdt.tree.fctree.FCTree; import crdt.tree.fctree.Operations.Add; import crdt.tree.fctree.Operations.ChX; import crdt.tree.fctree.Operations.Del; import java.io.Serializable; import java.util.Iterator; import java.util.LinkedList; /** * * @author Stephane Martin <stephane.martin@loria.fr> */ public class FastCycleBreaking<T> implements PostAction,Serializable { static final FCIdentifier garbageAddress = new FCIdentifier(-1, 1); FCNodeGf garbage; FCTree tree; T garbageName; public FastCycleBreaking() { } public FastCycleBreaking(T e) { garbageName=e; } @Override public void setTree(FCTree tree) { this.tree = tree; this.garbage = (FCNodeGf)tree.getNodeById(garbageAddress); if (garbage == null) { FCPosition pos = tree.getPositionFactory().createBetweenNode(null, null, garbageAddress); garbage = new FCNodeGf(tree.getRoot(), garbageName, pos, garbageAddress); tree.getRoot().addChildren(garbage); } } /** * * * We assume that at a move close a cycle. Because if it is not a case it * will be fixed previously and it doesn't a cycle. If a move break a cycle, * the headfather will be breaked and */ @Override public void postMove(ChX operation, FCNode nodef) { FCNodeGf node=(FCNodeGf)nodef; FCNodeGf hf=node.getHeadFather(); if(hf!=null && !hf.isDeleted() && hf.getFather()==garbage){ garbage.delChildren(hf); FCNodeGf oldFather=hf.getOldFather(); hf.setFather(oldFather); hf.setOldFather(null); oldFather.addChildren(hf); } LinkedList<FCNodeGf> pile = new LinkedList<FCNodeGf>(); FCNodeGf n = (FCNodeGf) node.getFather(); pile.add(node); FCNodeGf lowerID = node; while (n != tree.getRoot() && n != node) { //pile.push(n); pile.add(n); if (n.getId().compareTo(lowerID.getId()) > 0) { lowerID = n; } n = (FCNodeGf)n.getFather(); } if (n != tree.getRoot()) { /* Root lower id*/ lowerID.setOldFather((FCNodeGf)lowerID.getFather()); lowerID.getFather().delChildren(lowerID); lowerID.setFather(garbage); garbage.addChildren(lowerID); for (FCNodeGf nodehf : pile) { nodehf.setHeadFather(lowerID); } } } @Override public void postDel(Del operation, FCNode node) { Iterator<FCNodeGf> it = node.iterator(); while (it.hasNext()) { FCNodeGf no = it.next(); no.setOldFather(null); no.setFather(garbage); garbage.addChildren(no); FCNodeGf hf = no.getHeadFather(); if (hf != null && hf.getOldFather() != null) { garbage.delChildren(hf); hf.setFather(hf.getOldFather()); } } } @Override public void postAdd(Add operation, FCNode nodef) { FCNodeGf node=(FCNodeGf)nodef; if (node.getFather() == null) { node.setFather(garbage); garbage.addChildren(node); } } @Override public PostAction clone() { FastCycleBreaking ret = new FastCycleBreaking(); ret.tree = this.tree; ret.garbage = this.garbage; return ret; } }