int decRefCnt() {
   int refcnt = refcntUpdater.decrementAndGet(this);
   if (refcnt < 0) {
     throw new RuntimeException("refcnt:" + refcnt);
   }
   return refcnt;
 }
    protected void drain() {
      synchronized (this) {
        if (emitting) {
          missedEmitting++;
          return;
        }
        emitting = true;
        missedEmitting = 0;
      }
      final List<SourceSubscriber<T>.MergeItemSubscriber> subs = subscribers;
      final Subscriber<T> child = s;
      Object[] active = new Object[subs.size()];
      do {
        long r;

        outer:
        while ((r = requested) > 0) {
          int idx = lastIndex;
          synchronized (subs) {
            if (subs.size() == active.length) {
              active = subs.toArray(active);
            } else {
              active = subs.toArray();
            }
          }

          int resumeIndex = 0;
          int j = 0;
          for (Object o : active) {
            @SuppressWarnings("unchecked")
            MergeItemSubscriber e = (MergeItemSubscriber) o;
            if (e.index == idx) {
              resumeIndex = j;
              break;
            }
            j++;
          }
          int sumConsumed = 0;
          for (int i = 0; i < active.length; i++) {
            j = (i + resumeIndex) % active.length;

            @SuppressWarnings("unchecked")
            final MergeItemSubscriber e = (MergeItemSubscriber) active[j];
            final RxRingBuffer b = e.buffer;
            lastIndex = e.index;

            if (!e.once && b.peek() == null) {
              subs.remove(e);

              synchronized (guard) {
                this.active--;
              }
              csub.remove(e);

              e.release();

              subscribeNext();

              WIP.decrementAndGet(this);

              continue outer;
            }

            int consumed = 0;
            Object v;
            while (r > 0 && (v = b.poll()) != null) {
              nl.accept(child, v);
              if (child.isUnsubscribed()) {
                return;
              }
              r--;
              consumed++;
            }
            if (consumed > 0) {
              sumConsumed += consumed;
              REQUESTED.addAndGet(this, -consumed);
              e.requestMore(consumed);
            }
            if (r == 0) {
              break outer;
            }
          }
          if (sumConsumed == 0) {
            break;
          }
        }

        if (active.length == 0) {
          if (wip == 0) {
            child.onCompleted();
            return;
          }
        }
        synchronized (this) {
          if (missedEmitting == 0) {
            emitting = false;
            break;
          }
          missedEmitting = 0;
        }
      } while (true);
    }
 @Override
 public void onCompleted() {
   WIP.decrementAndGet(this);
   drain();
 }