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;
     }
   }
 }
  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;
        }
      }
    }
  }
    int findEndIndex(Node n, double key, boolean inclusive) {
      boolean exclusive = !inclusive;
      if (key < n.first()) return -1;
      if (key >= n.last()) {
        if (key == n.last() && exclusive) return n.len() - 2;
        return n.len() - 1;
      }
      int pos = n.findKeyIndex(key);
      if (pos < 0) pos = -(pos + 1);
      else if (!inclusive) pos--;

      if (pos == n.len()) pos--;
      return pos;
    }
 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;
     }
   }
 }