Esempio n. 1
0
 @Override
 public void call(final Subscriber<? super T> s) {
   if (state.casFirst(0, 1)) {
     final NotificationLite<T> nl = NotificationLite.instance();
     // drain queued notifications before subscription
     // we do this here before PassThruObserver so the consuming thread can do this before
     // putting itself in the line of the producer
     BufferedObserver<? super T> buffered = (BufferedObserver<? super T>) state.observerRef;
     Object o;
     while ((o = buffered.buffer.poll()) != null) {
       nl.accept(s, o);
     }
     // register real observer for pass-thru ... and drain any further events received on first
     // notification
     state.setObserverRef(new PassThruObserver<T>(s, buffered.buffer, state));
     s.add(
         Subscriptions.create(
             new Action0() {
               @Override
               public void call() {
                 state.setObserverRef(Subscribers.empty());
               }
             }));
   } else {
     s.onError(new IllegalStateException("Only one subscriber allowed!"));
   }
 }
Esempio n. 2
0
 private void drainIfNeededAndSwitchToActual() {
   final NotificationLite<T> nl = NotificationLite.instance();
   Object o;
   while ((o = buffer.poll()) != null) {
     nl.accept(this, o);
   }
   // now we can safely change over to the actual and get rid of the pass-thru
   // but only if not unsubscribed
   state.casObserverRef(this, actual);
 }
Esempio n. 3
0
    void complete(int id) {
      List<Object> localQueue;
      synchronized (guard) {
        if (id != index) {
          return;
        }
        active = false;
        if (!mainDone) {
          return;
        }
        if (emitting) {
          if (queue == null) {
            queue = new ArrayList<Object>();
          }
          queue.add(nl.completed());
          return;
        }

        localQueue = queue;
        queue = null;
        emitting = true;
      }

      drain(localQueue);
      serializedChild.onCompleted();
      unsubscribe();
    }
Esempio n. 4
0
 /** The common state. */
 static final class State<T> {
   /** Lite notifications of type T. */
   final NotificationLite<T> nl = NotificationLite.instance();
   /** The first observer or the one which buffers until the first arrives. */
   final AtomicReference<Observer<? super T>> observerRef =
       new AtomicReference<Observer<? super T>>(new BufferedObserver<T>());
   /** Allow a single subscriber only. */
   final AtomicBoolean first = new AtomicBoolean();
 }
Esempio n. 5
0
 private void drainIfNeededAndSwitchToActual() {
   Object o;
   while ((o = buffer.poll()) != null) {
     nl.accept(this, o);
   }
   // now we can safely change over to the actual and get rid of the pass-thru
   // but only if not unsubscribed
   observerRef.compareAndSet(this, actual);
 }
Esempio n. 6
0
 void drain(List<Object> localQueue) {
   if (localQueue == null) {
     return;
   }
   for (Object o : localQueue) {
     if (nl.isCompleted(o)) {
       serializedChild.onCompleted();
       break;
     } else if (nl.isError(o)) {
       serializedChild.onError(nl.getError(o));
       break;
     } else {
       @SuppressWarnings("unchecked")
       T t = (T) o;
       serializedChild.onNext(t);
       arbiter.produced(1);
     }
   }
 }
Esempio n. 7
0
  /**
   * This is a temporary observer between buffering and the actual that gets into the line of
   * notifications from the producer and will drain the queue of any items received during the race
   * of the initial drain and switching this.
   *
   * <p>It will then immediately swap itself out for the actual (after a single notification), but
   * since this is now being done on the same producer thread no further buffering will occur.
   */
  private static final class PassThruObserver<T> extends Subscriber<T> {

    private final Observer<? super T> actual;
    // this assumes single threaded synchronous notifications (the Rx contract for a single
    // Observer)
    private final ConcurrentLinkedQueue<Object> buffer;
    private final AtomicReference<Observer<? super T>> observerRef;
    private final NotificationLite<T> nl = NotificationLite.instance();

    PassThruObserver(
        Observer<? super T> actual,
        ConcurrentLinkedQueue<Object> buffer,
        AtomicReference<Observer<? super T>> observerRef) {
      this.actual = actual;
      this.buffer = buffer;
      this.observerRef = observerRef;
    }

    @Override
    public void onCompleted() {
      drainIfNeededAndSwitchToActual();
      actual.onCompleted();
    }

    @Override
    public void onError(Throwable e) {
      drainIfNeededAndSwitchToActual();
      actual.onError(e);
    }

    @Override
    public void onNext(T t) {
      drainIfNeededAndSwitchToActual();
      actual.onNext(t);
    }

    private void drainIfNeededAndSwitchToActual() {
      Object o;
      while ((o = buffer.poll()) != null) {
        nl.accept(this, o);
      }
      // now we can safely change over to the actual and get rid of the pass-thru
      // but only if not unsubscribed
      observerRef.compareAndSet(this, actual);
    }
  }
Esempio n. 8
0
  private static final class BufferedObserver<T> extends Subscriber<T> {
    private final ConcurrentLinkedQueue<Object> buffer = new ConcurrentLinkedQueue<Object>();
    private static final NotificationLite<Object> nl = NotificationLite.instance();

    @Override
    public void onCompleted() {
      buffer.add(nl.completed());
    }

    @Override
    public void onError(Throwable e) {
      buffer.add(nl.error(e));
    }

    @Override
    public void onNext(T t) {
      buffer.add(nl.next(t));
    }
  }
Esempio n. 9
0
    void error(Throwable e, int id) {
      List<Object> localQueue;
      synchronized (guard) {
        if (id != index) {
          return;
        }
        if (emitting) {
          if (queue == null) {
            queue = new ArrayList<Object>();
          }
          queue.add(nl.error(e));
          return;
        }

        localQueue = queue;
        queue = null;
        emitting = true;
      }

      drain(localQueue);
      serializedChild.onError(e);
      unsubscribe();
    }
Esempio n. 10
0
 @Override
 public void onCompleted() {
   List<Object> localQueue;
   synchronized (guard) {
     mainDone = true;
     if (active) {
       return;
     }
     if (emitting) {
       if (queue == null) {
         queue = new ArrayList<Object>();
       }
       queue.add(nl.completed());
       return;
     }
     localQueue = queue;
     queue = null;
     emitting = true;
   }
   drain(localQueue);
   serializedChild.onCompleted();
   unsubscribe();
 }
Esempio n. 11
0
 @Override
 public void onNext(T t) {
   buffer.add(nl.next(t));
 }
Esempio n. 12
0
 @Override
 public void onError(Throwable e) {
   buffer.add(nl.error(e));
 }
Esempio n. 13
0
 @Override
 public void onCompleted() {
   buffer.add(nl.completed());
 }
Esempio n. 14
0
  private static final class SwitchSubscriber<T> extends Subscriber<Observable<? extends T>> {
    final SerializedSubscriber<T> serializedChild;
    final SerialSubscription ssub;
    final Object guard = new Object();
    final NotificationLite<?> nl = NotificationLite.instance();
    final ProducerArbiter arbiter;

    /** Guarded by guard. */
    int index;
    /** Guarded by guard. */
    boolean active;
    /** Guarded by guard. */
    boolean mainDone;
    /** Guarded by guard. */
    List<Object> queue;
    /** Guarded by guard. */
    boolean emitting;
    /** Guarded by guard. */
    InnerSubscriber<T> currentSubscriber;

    SwitchSubscriber(Subscriber<? super T> child) {
      serializedChild = new SerializedSubscriber<T>(child);
      arbiter = new ProducerArbiter();
      ssub = new SerialSubscription();
      child.add(ssub);
      child.setProducer(
          new Producer() {

            @Override
            public void request(long n) {
              if (n > 0) {
                arbiter.request(n);
              }
            }
          });
    }

    @Override
    public void onNext(Observable<? extends T> t) {
      final int id;
      synchronized (guard) {
        id = ++index;
        active = true;
        currentSubscriber = new InnerSubscriber<T>(id, arbiter, this);
      }
      ssub.set(currentSubscriber);
      t.unsafeSubscribe(currentSubscriber);
    }

    @Override
    public void onError(Throwable e) {
      serializedChild.onError(e);
      unsubscribe();
    }

    @Override
    public void onCompleted() {
      List<Object> localQueue;
      synchronized (guard) {
        mainDone = true;
        if (active) {
          return;
        }
        if (emitting) {
          if (queue == null) {
            queue = new ArrayList<Object>();
          }
          queue.add(nl.completed());
          return;
        }
        localQueue = queue;
        queue = null;
        emitting = true;
      }
      drain(localQueue);
      serializedChild.onCompleted();
      unsubscribe();
    }

    void emit(T value, int id, InnerSubscriber<T> innerSubscriber) {
      List<Object> localQueue;
      synchronized (guard) {
        if (id != index) {
          return;
        }
        if (emitting) {
          if (queue == null) {
            queue = new ArrayList<Object>();
          }
          queue.add(value);
          return;
        }
        localQueue = queue;
        queue = null;
        emitting = true;
      }
      boolean once = true;
      boolean skipFinal = false;
      try {
        do {
          drain(localQueue);
          if (once) {
            once = false;
            serializedChild.onNext(value);
            arbiter.produced(1);
          }
          synchronized (guard) {
            localQueue = queue;
            queue = null;
            if (localQueue == null) {
              emitting = false;
              skipFinal = true;
              break;
            }
          }
        } while (!serializedChild.isUnsubscribed());
      } finally {
        if (!skipFinal) {
          synchronized (guard) {
            emitting = false;
          }
        }
      }
    }

    void drain(List<Object> localQueue) {
      if (localQueue == null) {
        return;
      }
      for (Object o : localQueue) {
        if (nl.isCompleted(o)) {
          serializedChild.onCompleted();
          break;
        } else if (nl.isError(o)) {
          serializedChild.onError(nl.getError(o));
          break;
        } else {
          @SuppressWarnings("unchecked")
          T t = (T) o;
          serializedChild.onNext(t);
          arbiter.produced(1);
        }
      }
    }

    void error(Throwable e, int id) {
      List<Object> localQueue;
      synchronized (guard) {
        if (id != index) {
          return;
        }
        if (emitting) {
          if (queue == null) {
            queue = new ArrayList<Object>();
          }
          queue.add(nl.error(e));
          return;
        }

        localQueue = queue;
        queue = null;
        emitting = true;
      }

      drain(localQueue);
      serializedChild.onError(e);
      unsubscribe();
    }

    void complete(int id) {
      List<Object> localQueue;
      synchronized (guard) {
        if (id != index) {
          return;
        }
        active = false;
        if (!mainDone) {
          return;
        }
        if (emitting) {
          if (queue == null) {
            queue = new ArrayList<Object>();
          }
          queue.add(nl.completed());
          return;
        }

        localQueue = queue;
        queue = null;
        emitting = true;
      }

      drain(localQueue);
      serializedChild.onCompleted();
      unsubscribe();
    }
  }
Esempio n. 15
0
  static final class SourceSubscriber<T> extends Subscriber<Observable<? extends T>> {
    final NotificationLite<T> nl = NotificationLite.instance();
    final int maxConcurrency;
    final Subscriber<T> s;
    final CompositeSubscription csub;
    final Object guard;

    volatile int wip;

    @SuppressWarnings("rawtypes")
    static final AtomicIntegerFieldUpdater<SourceSubscriber> WIP =
        AtomicIntegerFieldUpdater.newUpdater(SourceSubscriber.class, "wip");

    volatile int sourceIndex;

    @SuppressWarnings("rawtypes")
    static final AtomicIntegerFieldUpdater<SourceSubscriber> SOURCE_INDEX =
        AtomicIntegerFieldUpdater.newUpdater(SourceSubscriber.class, "sourceIndex");

    /** Guarded by guard. */
    int active;
    /** Guarded by guard. */
    final Queue<Observable<? extends T>> queue;

    /** Indicates the emitting phase. Guarded by this. */
    boolean emitting;
    /** Counts the missed emitting calls. Guarded by this. */
    int missedEmitting;
    /** The last buffer index in the round-robin drain scheme. Accessed while emitting == true. */
    int lastIndex;

    /** Guarded by itself. */
    final List<MergeItemSubscriber> subscribers;

    volatile long requested;

    @SuppressWarnings("rawtypes")
    static final AtomicLongFieldUpdater<SourceSubscriber> REQUESTED =
        AtomicLongFieldUpdater.newUpdater(SourceSubscriber.class, "requested");

    public SourceSubscriber(int maxConcurrency, Subscriber<T> s, CompositeSubscription csub) {
      super(s);
      this.maxConcurrency = maxConcurrency;
      this.s = s;
      this.csub = csub;
      this.guard = new Object();
      this.queue = new ArrayDeque<Observable<? extends T>>(maxConcurrency);
      this.subscribers = Collections.synchronizedList(new ArrayList<MergeItemSubscriber>());
      this.wip = 1;
    }

    @Override
    public void onStart() {
      request(maxConcurrency);
    }

    @Override
    public void onNext(Observable<? extends T> t) {
      synchronized (guard) {
        queue.add(t);
      }
      subscribeNext();
    }

    void subscribeNext() {
      Observable<? extends T> t;
      synchronized (guard) {
        t = queue.peek();
        if (t == null || active >= maxConcurrency) {
          return;
        }
        active++;
        queue.poll();
      }

      MergeItemSubscriber itemSub = new MergeItemSubscriber(SOURCE_INDEX.getAndIncrement(this));
      subscribers.add(itemSub);

      csub.add(itemSub);

      WIP.incrementAndGet(this);

      t.unsafeSubscribe(itemSub);

      request(1);
    }

    @Override
    public void onError(Throwable e) {
      Object[] active;
      synchronized (subscribers) {
        active = subscribers.toArray();
        subscribers.clear();
      }

      try {
        s.onError(e);

        unsubscribe();
      } finally {
        for (Object o : active) {
          @SuppressWarnings("unchecked")
          MergeItemSubscriber a = (MergeItemSubscriber) o;
          a.release();
        }
      }
    }

    @Override
    public void onCompleted() {
      WIP.decrementAndGet(this);
      drain();
    }

    protected void downstreamRequest(long n) {
      for (; ; ) {
        long r = requested;
        long u;
        if (r != Long.MAX_VALUE && n == Long.MAX_VALUE) {
          u = Long.MAX_VALUE;
        } else if (r + n < 0) {
          u = Long.MAX_VALUE;
        } else {
          u = r + n;
        }
        if (REQUESTED.compareAndSet(this, r, u)) {
          break;
        }
      }
      drain();
    }

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

    final class MergeItemSubscriber extends Subscriber<T> {
      volatile boolean once = true;
      final int index;
      final RxRingBuffer buffer;

      public MergeItemSubscriber(int index) {
        buffer = RxRingBuffer.getSpmcInstance();
        this.index = index;
      }

      @Override
      public void onStart() {
        request(RxRingBuffer.SIZE);
      }

      @Override
      public void onNext(T t) {
        try {
          buffer.onNext(t);
        } catch (MissingBackpressureException ex) {
          onError(ex);
          return;
        }

        drain();
      }

      @Override
      public void onError(Throwable e) {
        SourceSubscriber.this.onError(e);
      }

      @Override
      public void onCompleted() {
        if (once) {
          once = false;
          drain();
        }
      }
      /** Request more from upstream. */
      void requestMore(long n) {
        request(n);
      }

      void release() {
        // NO-OP for now
        buffer.release();
      }
    }
  }
Esempio n. 16
0
    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);
    }