/**
* 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.set.observedremove;
import crdt.CRDTMessage;
import crdt.set.CRDTSet;
import crdt.set.ConvergentSet;
import java.util.*;
/**
*
* @author score
*/
public class ConvergentOrSet<T> extends ConvergentSet<T> {
private HashMap<T, HashSet<Tag>> mapA;
private HashMap<T, HashSet<Tag>> mapR;
private int numOp;
HashSet<T> lookup;
public ConvergentOrSet() {
mapA = new HashMap<T, HashSet<Tag>>();
mapR = new HashMap<T, HashSet<Tag>>();
numOp = 0;
lookup = new HashSet();
}
@Override
public Set<T> lookup() {
return lookup;
}
@Override
public void applyOneRemote(CRDTMessage set) {
ConvergentOrSet oSetC = ((ConvergentOrSet) set).clone();
HashMap<T, HashSet<Tag>> statA = oSetC.getMapA();//for add
HashMap<T, HashSet<Tag>> statR = oSetC.getMapR();//for remove
boolean before,after;
for (T t : statA.keySet()) {
before = lookup.contains(t);
if (mapA.get(t) == null) { //receive first add
mapA.put(t, statA.get(t));
} else {
mapA.get(t).addAll(statA.get(t));
}
if (statR.containsKey(t)) {
if (mapR.get(t) == null) { //receive first remove
mapR.put(t, statR.get(t));
} else {//remove elements with several tags
mapR.get(t).addAll(statR.get(t));
}
}
if (!mapR.keySet().contains(t)
|| (mapR.keySet().contains(t) && mapA.get(t).size() > mapR.get(t).size())) {
lookup.add(t);
}
if (mapR.keySet().contains(t) && mapR.get(t).size() == mapA.get(t).size()) {
lookup.remove(t);
}
after = lookup.contains(t);
if (!before && after) {
notifyAdd(t);
}
if (before && !after) {
notifyDel(t);
}
}
}
HashMap getMapA() {
return mapA;
}
HashMap getMapR() {
return mapR;
}
void setMapA(HashMap<T, HashSet<Tag>> t) {
mapA.clear();
mapA = t;
}
void setMapR(HashMap<T, HashSet<Tag>> t) {
mapR.clear();
mapR = t;
}
@Override
public ConvergentOrSet<T> innerAdd(T t) {
final Tag tag = new Tag(getReplicaNumber(), ++numOp); // creat new tag
if (!mapA.containsKey(t)) {
mapA.put(t, new HashSet<Tag>());
}
mapA.get(t).add(tag);
lookup.add(t);
return this;
}
@Override
public ConvergentOrSet<T> innerRemove(T t) {
if (!mapR.containsKey(t)) {
mapR.put(t, new HashSet<Tag>());
}
mapR.get(t).addAll(mapA.get(t));
lookup.remove(t);
return this;
}
@Override
public boolean contains(T t) {
return(this.lookup().contains(t));
}
int getNumOp() {
return numOp;
}
void setNumOp(int o) {
this.numOp = o;
}
@Override
public CRDTSet<T> create() {
return new ConvergentOrSet();
}
@Override
public ConvergentOrSet<T> clone() {
ConvergentOrSet<T> clone = new ConvergentOrSet<T>();
clone.mapA = (HashMap<T, HashSet<Tag>>) this.mapA.clone();
clone.mapR = (HashMap<T, HashSet<Tag>>) this.mapR.clone();
clone.numOp = this.numOp;
clone.lookup = (HashSet<T>) this.lookup.clone();
return clone;
}
}