package skiplists.transactional; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.deuce.Atomic; import contention.abstractions.CompositionalIntSet; import contention.abstractions.CompositionalMap; import contention.abstractions.MaintenanceAlg; public class TransactionalFriendlyOptimizedSkipListSet<K,V> implements CompositionalIntSet, CompositionalMap<K,V>, MaintenanceAlg { static volatile int maxHeight = 1; static final int totalHeight = 25; /** The thread-private PRNG */ final private static ThreadLocal<Random> s_random = new ThreadLocal<Random>() { @Override protected synchronized Random initialValue() { return new Random(); } }; private class MaintenanceThread extends Thread { TransactionalFriendlyOptimizedSkipListSet map; MaintenanceThread(TransactionalFriendlyOptimizedSkipListSet map) { this.map = map; } public void run() { map.doMaintenance(); } } static class Index { final Node node; final Index down; volatile Index right; Index up; /** * Creates index node with given values. */ Index(Node node, Index down, Index right) { this.node = node; this.down = down; this.right = right; this.up = null; } } static final class Node { final int key; volatile Node next, prev; volatile boolean deleted, removed; int maxLevel; Index up; /** * Creates a new regular node. */ Node(int key) { this.key = key; this.deleted = false; this.removed = false; this.maxLevel = 0; this.up = null; } } // state private final Node begin = new Node(Integer.MIN_VALUE); private final Node end = new Node(Integer.MAX_VALUE); private final ArrayList<Index> beginList = new ArrayList<Index>(); private Index startBegin; volatile boolean stop = false; private final MaintenanceThread mainThd = new MaintenanceThread(this); private long heightChanges = 0; // Constructors public TransactionalFriendlyOptimizedSkipListSet() { begin.maxLevel = totalHeight - 1; end.maxLevel = totalHeight - 1; Index prevBegin = null, prevEnd = null, oldBegin = null, oldEnd = null; begin.next = end; end.prev = begin; for (int i = 1; i < totalHeight; i++) { oldBegin = prevBegin; oldEnd = prevEnd; prevEnd = new Index(end, prevEnd, null); prevBegin = new Index(begin, prevBegin, prevEnd); if (i == 1) { begin.up = prevBegin; end.up = prevEnd; } else { oldBegin.up = prevBegin; oldEnd.up = prevEnd; } beginList.add(prevBegin); } startBegin = beginList.get(0); this.startMaintenance(); } @Override public void fill(final int range, final long size) { while (this.size() < size) { this.addInt(s_random.get().nextInt(range)); } } @Atomic public boolean addTrans(int x, Node currentNode) { Node nextNode; while (currentNode.removed) { currentNode = currentNode.prev; } nextNode = currentNode.next; for (;;) { if (nextNode.key == x) { if (!nextNode.deleted) { return false; } else { nextNode.deleted = false; return true; } } else if (nextNode.key > x) { Node newNode = new Node(x); newNode.next = nextNode; newNode.prev = currentNode; nextNode.prev = newNode; currentNode.next = newNode; return true; } else { currentNode = nextNode; nextNode = currentNode.next; } } } @Override public boolean addInt(int x) { Index nextIndex, currentIndex; Node currentNode; currentIndex = startBegin; for (;;) { nextIndex = currentIndex.right; for (;;) { // should only have to go down 1 lvl in the case of null next if (nextIndex == null) { break; } if (nextIndex.node.key >= x) { break; } else { currentIndex = nextIndex; nextIndex = currentIndex.right; } } if (currentIndex.down == null) { break; } currentIndex = currentIndex.down; } // System.out.println(traversed); currentNode = currentIndex.node; return addTrans(x, currentNode); } @Atomic private boolean removeTrans(int x, Node currentNode) { Node nextNode; while (currentNode.removed) { currentNode = currentNode.prev; } nextNode = currentNode.next; for (;;) { if (nextNode.key == x) { if (!nextNode.deleted) { nextNode.deleted = true; return true; } else { return false; } } else if (nextNode.key > x) { return false; } else { currentNode = nextNode; nextNode = currentNode.next; } } } @Override public boolean removeInt(int x) { Index nextIndex, currentIndex; Node currentNode; currentIndex = startBegin; for (;;) { nextIndex = currentIndex.right; for (;;) { // should only have to go down 1 lvl in the case of null next if (nextIndex == null) { break; } if (nextIndex.node.key >= x) { break; } else { currentIndex = nextIndex; nextIndex = currentIndex.right; } } if (currentIndex.down == null) { break; } currentIndex = currentIndex.down; } // System.out.println(traversed); currentNode = currentIndex.node; return removeTrans(x, currentNode); } @Atomic public boolean containsTrans(int x, Node currentNode) { Node nextNode; while (currentNode.removed) { currentNode = currentNode.prev; } nextNode = currentNode.next; for (;;) { if (nextNode.key == x) { if (!nextNode.deleted) { return true; } else { return false; } } else if (nextNode.key > x) { return false; } else { currentNode = nextNode; nextNode = currentNode.next; } } } @Override public boolean containsInt(int x) { Index nextIndex, currentIndex; Node currentNode; currentIndex = startBegin; for (;;) { nextIndex = currentIndex.right; for (;;) { // should only have to go down 1 lvl in the case of null next if (nextIndex == null) { break; } if (nextIndex.node.key >= x) { break; } else { currentIndex = nextIndex; nextIndex = currentIndex.right; } } if (currentIndex.down == null) { break; } currentIndex = currentIndex.down; } // System.out.println(traversed); currentNode = currentIndex.node; return containsTrans(x, currentNode); } @Override public Object getInt(int x) { if (containsInt(x)) return x; else return null; } @Override @Atomic public boolean addAll(Collection<Integer> c) { boolean result = true; for (int x : c) result &= this.addInt(x); return result; } @Override @Atomic public boolean removeAll(Collection<Integer> c) { boolean result = true; for (int x : c) if (!this.removeInt(x)) result = false; return result; } public int totalSize() { int count = 0; Node current = begin.next; ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<Integer, Integer>(); while (current != end) { count++; if (map.putIfAbsent((Integer) current.key, (Integer) current.key) != null) { System.out.println("Error found 2: " + current.key); } // System.out.print(current.key); current = current.next; // System.out.print(current.maxLevel + ", " + current.level + " "); } System.out.println(); return count; } @Override @Atomic public int size() { int count = 0; Node current = begin.next; while (current != end) { if (!current.deleted) { count++; } current = current.next; // System.out.print(current.maxLevel + ", " + current.level + " "); } // System.out.println(); return count; } @Override public void clear() { return; } // @Override // @Atomic // public Object putIfAbsent(int x, int y) { // if (!contains(y)) // add(x); // return null; // } public boolean stopMaintenance() { this.stop = true; try { this.mainThd.join(); } catch (InterruptedException e) { e.printStackTrace(); } return true; } public boolean startMaintenance() { this.mainThd.start(); return true; } private void doMaintenance() { int count; int height; while (!stop) { count = this.removalTraversal(); // System.out.println("Count: " + count); height = (int) (Math.log(count) / Math.log(2)) + 1; // System.out.println("Count, height: " + count + ", " + height); if (height > totalHeight) { height = totalHeight; } // this.recCalculateHeight(this.begin, this.end, height - 1, count); // this.recCalculateReccomendedHeight(this.begin, this.end, height - // 1, count); LinkedList<Node> next = null; for (int i = 0; i < height; i++) { next = doHeight(next, i); if (next.size() <= 3) break; } this.raiseNodes(); setMaxHeight(height); // System.out.println("height: " + height); setStartBegin(height - 2); } System.out.println("Height Changes: " + heightChanges); } // @Atomic private void setMaxHeight(int height) { maxHeight = height; } // @Atomic private void setStartBegin(int height) { startBegin = beginList.get(Math.max(0, height)); } @Atomic(metainf = "maint") private Node getNext(Node node) { return node.next; } @Atomic(metainf = "maint") private boolean isDeleted(Node node) { return node.deleted; } @Atomic(metainf = "maint") public boolean removeMaint(Node prev) { Node node = prev.next; if (!node.deleted) { return false; } Node next = node.next; node.removed = true; prev.next = next; next.prev = prev; return true; } private int removalTraversal() { Node node, next; int count = 0, delCount = 0; // final double when = 0.05 + 1/Math.pow(10, Math.max(this.totalCount, // 1)/Math.max(this.deletedCount, 1)); count = 0; node = begin; next = node; while (node != end) { next = this.getNext(node); if (isDeleted(next)) { delCount++; count++; } else { count++; } if (isDeleted(next) && next.maxLevel == 0 /* * && Math.random() > .99 * /*&& Math.random() <= * when */) { // System.out.println("removing node"); removeMaint(node); // node = node.next; } else { node = node.next; } } return count; } public LinkedList<Node> doHeight(LinkedList<Node> list, int height) { LinkedList<Node> newList; Node prev, curr, next; newList = new LinkedList<Node>(); // if(list != null) { // System.out.println("height, list size: " + height + ", " + // list.size()); // } if (height == 0) { prev = getNext(begin); if (prev == end) return newList; curr = getNext(prev); if (curr == end) return newList; next = getNext(curr); if (next == end) return newList; } else { if (list.size() <= 3) return newList; prev = list.removeFirst(); curr = list.removeFirst(); next = list.removeFirst(); } if (prev.maxLevel > height) { newList.add(prev); } while (true) { if (curr.maxLevel > height) { newList.add(curr); } else if (prev.maxLevel <= height && curr.maxLevel <= height && next.maxLevel <= height) { curr.maxLevel++; // if(curr.maxLevel != height + 1) // System.out.println("error in doHeight: " + curr.key); newList.add(curr); } prev = curr; curr = next; if (height == 0) { next = getNext(next); // System.out.println(next.maxLevel); if (next == end) break; } else { if (list.isEmpty()) break; next = list.removeFirst(); } } if (curr.maxLevel > height) { newList.add(curr); } return newList; } public void raiseNodes() { Node node, next; Index nodeIndex, nextIndex, tmpIndex; for (int i = 1; i < totalHeight; i++) { node = begin; next = node; while (node != end) { next = getNext(node); // should also check if deleted == false? while (next.maxLevel < i) { next = getNext(next); } nextIndex = next.up; if (nextIndex == null) { nextIndex = new Index(next, null, null); next.up = nextIndex; } for (int j = 2; j < i; j++) { nextIndex = nextIndex.up; } if (nextIndex.up == null) { heightChanges++; tmpIndex = new Index(next, nextIndex, null); nextIndex.up = tmpIndex; nextIndex = tmpIndex; } else { nextIndex = nextIndex.up; } nodeIndex = node.up; for (int j = 2; j <= i; j++) { nodeIndex = nodeIndex.up; } if (nodeIndex.right != nextIndex) { nodeIndex.right = nextIndex; } node = next; } } } @Override public long getStructMods() { // TODO Auto-generated method stub return 0; } @Override public int numNodes() { return this.totalSize(); } @Override @Atomic(metainf = "regular") public V putIfAbsent(K x, V y) { if (!containsInt((Integer) y)) addInt((Integer) x); return null; } @Override @Atomic(metainf = "regular") public Object putIfAbsent(int x, int y) { if (!containsInt(y)) addInt(x); return null; } @Override public V get(Object key) { if (containsInt((Integer) key)) return (V) key; else return null; } // @Override // public V putIfAbsent(K k, V v) { // // TODO Auto-generated method stub // return null; // } @Override public V remove(Object key) { if (removeInt((Integer) key)) return (V) key; else return null; } @Override public boolean containsKey(Object key) { return containsInt((Integer) key); } @Override public boolean containsValue(Object value) { // TODO Auto-generated method stub return false; } @Override public Set<java.util.Map.Entry<K, V>> entrySet() { // TODO Auto-generated method stub return null; } @Override public boolean isEmpty() { // TODO Auto-generated method stub return false; } @Override public Set<K> keySet() { // TODO Auto-generated method stub return null; } @Override public V put(K key, V value) { // TODO Auto-generated method stub return null; } @Override public void putAll(Map<? extends K, ? extends V> m) { // TODO Auto-generated method stub } @Override public Collection<V> values() { // TODO Auto-generated method stub return null; } }