// 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;
     }
   }
 }