// no concurrent read/write is assumed public V put(double key, V value) { if (value == null) throw new NullPointerException(); // not incrementing b's refcnt, so need not release it. Node b = skipListMap.findGrandPredecessor(key); if (b == null) b = head; Node n = b.next; if (n == null) { n = Node.alloc(); n.put(key, value, this); n.next = null; b.next = n; return null; } Node f = n.next; if (f == null) { // put (key,value) into node n Object val = n.put(key, value, this); return (V) val; } else { assert f.len() > 0 && f.first() >= key; if (f.first() == key) { Object val = f.put(key, value, this); return (V) val; } else { Object val = n.put(key, value, this); return (V) val; } } }
Node ceilingNode(double key) { for (; ; ) { Node b = skipListMap.findGrandPredecessor(key, refCntCallback); if (b == null) b = head; if (b != head && key <= b.last()) { return b; } assert b == head || b.last() < key; Node n = safeNext(b); release(b); if (n == null) { return null; } else if (key <= n.last()) { return n; } Node f = safeNext(n); release(n); if (f == null) { return null; } else { if (isInconsistentNextNode(f, key)) { release(f); continue; } return f; } } }
public void doSanityCheck() { int count = 0; double prevKey = Double.MIN_VALUE; Node n = safeNext(head); while (n != null) { count++; if (!skipListMap.containsKey(n.first())) { System.out.println("Node n not in skiplistMap:" + n.first()); n._print(); } if (n.first() < prevKey) { System.out.println("Error in ordering, prevKey:" + prevKey + ", n:" + n); } prevKey = n.first(); Node next = safeNext(n); release(n); n = next; } if (skipListMap.size() != count) { System.out.println("skipListMap.size:" + skipListMap.size() + ", count:" + count); } }
V putAtomic(double key, V value, boolean onlyIfAbsent) { if (value == null) throw new NullPointerException(); for (; ; ) { Node b = skipListMap.findGrandPredecessor(key, refCntCallback); if (b == null) b = head; if (b != head && b.first() <= key && key <= b.last()) { release(b); continue; } assert b == head || b.last() < key; Node n = safeNext(b); if (n == null) { if (b.appendNewAtomic(key, value, this)) { release(b); return null; } else { release(b); continue; } } else if (n.first() <= key && key <= n.last()) { Object val = n.putAtomic(key, value, b, onlyIfAbsent, this); release(b, n); if (val == Retry) continue; return (V) val; } Node f = safeNext(n); if (f == null) { Object val = n.putAtomic(key, value, b, onlyIfAbsent, this); release(b, n); if (val == Retry) continue; return (V) val; } else { if (f.first() == key) { Object val = f.putAtomic(key, value, n, onlyIfAbsent, this); release(b, n, f); if (val == Retry) continue; return (V) val; } else { if (key > f.first()) { // inconsistent read, retry release(b, n, f); continue; } Object val = n.putAtomic(key, value, b, onlyIfAbsent, this); release(b, n, f); if (val == Retry) continue; return (V) val; } } } }
V doReplace(double key, V old, V value) { for (; ; ) { Node b = skipListMap.findGrandPredecessor(key, refCntCallback); if (b == null) b = head; if (b != head && b.first() <= key && key <= b.last()) { // can happen if there's inconsistency between skipListMap and orderedMap(this). // The inconsistency can happen from Node.putAtomicReally(), // where it adds to, and removes from skiplistMap. Object val = b.replace(key, old, value); release(b); if (val == Retry) continue; return (V) val; } assert b == head || b.last() < key; Node n = safeNext(b); release(b); if (n == null) { return null; } else if (n.first() <= key && key <= n.last()) { Object val = n.replace(key, old, value); release(n); if (val == Retry) continue; return (V) val; } Node f = safeNext(n); release(n); if (f == null) { return null; } else { if (isInconsistentNextNode(f, key)) { release(f); continue; } Object val = f.replace(key, old, value); release(f); if (val == Retry) continue; return (V) val; } } }