Package com.linkedin.databus.client.consumer

Source Code of com.linkedin.databus.client.consumer.MultiConsumerCallback$TimestampedFutureComparator

package com.linkedin.databus.client.consumer;
/*
*
* Copyright 2013 LinkedIn Corp. All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/


import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.avro.Schema;
import org.apache.log4j.Logger;

import com.linkedin.databus.client.pub.ConsumerCallbackResult;
import com.linkedin.databus.client.pub.DatabusCombinedConsumer;
import com.linkedin.databus.client.pub.DatabusStreamConsumer;
import com.linkedin.databus.client.pub.DbusEventDecoder;
import com.linkedin.databus.client.pub.SCN;
import com.linkedin.databus.client.pub.mbean.ConsumerCallbackStats;
import com.linkedin.databus.client.pub.mbean.UnifiedClientStats;
import com.linkedin.databus.core.DbusConstants;
import com.linkedin.databus.core.DbusEvent;
import com.linkedin.databus.core.data_model.DatabusSubscription;
import com.linkedin.databus.core.util.IdNamePair;

/**
* Implements callbacks to multiple databus consumers in parallel. It also enforces
* a configurable time budget.
*/
public class MultiConsumerCallback implements DatabusStreamConsumer
{
  public final String MODULE = MultiConsumerCallback.class.getName();
  public Logger _log;

  private final List<DatabusV2ConsumerRegistration> _registrations;
  private final ExecutorService _executorService;
  private final List<ConsumerCallable<ConsumerCallbackResult>> _currentBatch;
  private final ConsumerCallbackFactory<DatabusCombinedConsumer> _callbackFactory;
  private final long _timeBudgetNanos;
  private Map<Long, IdNamePair> _sourceMap;
  private long _runCallsCounter;
  private final PriorityQueue<TimestampedFuture<ConsumerCallbackResult>> _submittedCalls;
  private final Lock _lock = new ReentrantLock();
  private final LoggingConsumer _loggingConsumer;

  //local stats accumulators
  private final ConsumerCallbackStats _consumerStats;
  private final UnifiedClientStats _unifiedClientStats;


  // used only by tests
  public MultiConsumerCallback(List<DatabusV2ConsumerRegistration> registrations,
                               ExecutorService executorService,
                               long timeBudgetMs,
                               ConsumerCallbackFactory<DatabusCombinedConsumer> callbackFactory)
  {
    this(registrations, executorService, timeBudgetMs, callbackFactory, null, null, null, null);
  }

  public MultiConsumerCallback(List<DatabusV2ConsumerRegistration> registrations,
                               ExecutorService executorService,
                               long timeBudgetMs,
                               ConsumerCallbackFactory<DatabusCombinedConsumer> callbackFactory,
                               ConsumerCallbackStats consumerStats,    // specific to relay or bootstrap mode, not both
                               UnifiedClientStats unifiedClientStats,  // used in both relay and bootstrap mode
                               LoggingConsumer loggingConsumer,
                               Logger log)
  {
    _registrations = registrations;
    _executorService = executorService;
    _timeBudgetNanos = timeBudgetMs * DbusConstants.NUM_NSECS_IN_MSEC;
    _currentBatch = new ArrayList<ConsumerCallable<ConsumerCallbackResult>>(2048);
    _callbackFactory = callbackFactory;
    _runCallsCounter = 0;
    _submittedCalls =
        new PriorityQueue<MultiConsumerCallback.TimestampedFuture<ConsumerCallbackResult>>(100,
            new TimestampedFutureComparator<ConsumerCallbackResult>());
    _consumerStats = consumerStats;
    _unifiedClientStats = unifiedClientStats;
    // loggingConsumer, log may be null in unit tests
    _loggingConsumer = loggingConsumer;
    if (null != log)
    {
      _log = log;
    }
    else
    {
      _log = Logger.getLogger(MODULE);
    }
  }

  private ConsumerCallbackResult submitBatch(long curNanos, boolean barrierBefore,
                                             boolean barrierAfter)
  {
    ++_runCallsCounter;
    ConsumerCallbackResult retValue = ConsumerCallbackResult.SUCCESS;
    if (0 >= curNanos) curNanos = System.nanoTime();
    try
    {
      if (barrierBefore) retValue = flushCallQueue(curNanos);

      if (ConsumerCallbackResult.isSuccess(retValue))
      {
        String batchName = _currentBatch.size() > 0 ? _currentBatch.get(0).getClass().getSimpleName()
                                                    : "";
        for (ConsumerCallable<ConsumerCallbackResult> call: _currentBatch)
        {
          Future<ConsumerCallbackResult> future = _executorService.submit(call);
          _submittedCalls.add(new TimestampedFuture<ConsumerCallbackResult>(call, future,
              batchName, ++_runCallsCounter));

        }
      }
      _currentBatch.clear();

      if (ConsumerCallbackResult.isSuccess(retValue))
      {
        ConsumerCallbackResult retValue2 = barrierAfter ? flushCallQueue(curNanos)
                                                        : cleanUpCallQueue(curNanos);
        retValue = ConsumerCallbackResult.max(retValue, retValue2);
      }
    }
    catch (RuntimeException e)
    {
      _log.error("internal callback error: " + e.getMessage(), e);
      retValue = ConsumerCallbackResult.ERROR;
    }
    return retValue;
  }

  private ConsumerCallbackResult cleanUpCallQueue(long curNanos)
  {
    ConsumerCallbackResult result = ConsumerCallbackResult.SUCCESS;
    TimestampedFuture<ConsumerCallbackResult> top = null;
    if (0 > curNanos) curNanos = System.nanoTime();
    long timeoutNanos = _timeBudgetNanos > 0 ? curNanos - _timeBudgetNanos : 0;

    //remove completed or expired calls at the head of the queue
    while ((top = _submittedCalls.peek()) != null &&
           (timeoutNanos >= top.getTimestamp() || top.getFuture().isDone()))
    {
      ConsumerCallbackResult callRes = null;
      if (top.getFuture().isDone())
      {
        callRes = getCallResult(top.getFuture(), top.getCallType(), -1);
      }
      else
      {
        //timeout
        callRes = ConsumerCallbackResult.ERROR;
        top.getFuture().cancel(true);
        _log.error("callback timeout: " + top.getCallType() + "; runtime = " +
                  ((top.getTimestamp() - curNanos) / DbusConstants.NUM_NSECS_IN_MSEC)
                  + " ms; try increasing client.connectionDefaults.consumerTimeBudgetMs");
      }

      result = ConsumerCallbackResult.max(result, callRes);
      if (ConsumerCallbackResult.isFailure(result))
      {
        _log.error("error detected; cancelling all " + _submittedCalls.size() + " outstanding callbacks ");
        cancelCalls();
      }
      //remove the call
      dequeueTopFuture(result);
    }

    return result;
  }


  private void dequeueTopFuture(ConsumerCallbackResult result)
  {
    _lock.lock();
    try
    {
      TimestampedFuture<ConsumerCallbackResult> future = _submittedCalls.poll();

      if (null == future) return;
      ConsumerCallable<ConsumerCallbackResult> callable = future.getCallable();
      callable.endCall(result);
    }
    finally
    {
      _lock.unlock();
    }
  }

  private ConsumerCallbackResult getCallResult(Future<ConsumerCallbackResult> future,
                                               String callType,
                                               long timeoutNanos)
  {
    try
    {
      if (timeoutNanos == 0)
      {
        _log.error("Exhausted time budget of " + _timeBudgetNanos/DbusConstants.NUM_NSECS_IN_MSEC +
                  "ms. Skipping remaining callbacks of type " + callType);
        throw new TimeoutException("No time remaining in a timeout budget of " +
                                   (_timeBudgetNanos/DbusConstants.NUM_NSECS_IN_MSEC) + " ms");
        // Exception caught below
      }

      ConsumerCallbackResult result =  timeoutNanos < 0 ? future.get()
                                                         : future.get(timeoutNanos, TimeUnit.NANOSECONDS);
      if (result == null)
      {
        result = ConsumerCallbackResult.ERROR;
        _log.error("Client application callback (" + callType + ") returned null");
      }
      else if (!ConsumerCallbackResult.isSuccess(result))
      {
        _log.error("Client application callback (" + callType + ") returned error:" + result);
      }
      return result;
    }
    catch (ExecutionException ee)
    {
      // Consumer threw an exception while fielding the callback.
      _log.error("Uncaught exception in client application callback (" + callType + "): " + ee.getCause().getCause(), ee.getCause());
    }
    catch (InterruptedException ee)
    {
      _log.warn("Client application callback (" + callType + ") interrupted");
    }
    catch (TimeoutException te)
    {
      _log.error("Client application timed out handling callback: " + callType +
                "; Try increasing client.connectionDefaults.consumerTimeBudgetMs " +
                " or client.connectionDefaults.bstConsumerTimeBudgetMs");
    }

    return ConsumerCallbackResult.ERROR;
  }

  /** Cancel all outstanding calls */
  private void cancelCalls()
  {
    //cancel all remaining outstanding calls
    TimestampedFuture<ConsumerCallbackResult> top = null;
    while ( (top = _submittedCalls.poll()) != null)
    {
      try
      {
        if (! top.getFuture().isDone()) top.getFuture().cancel(true);
        top.getCallable().endCall(ConsumerCallbackResult.ERROR);
      }
      catch (RuntimeException e)
      {
        _log.error("unable to cancel call: " + top.getCallType() + ": " + e.getMessage(), e);
      }
    }
  }

  /** Acts as a barrier for all outstanding calls in the call queue */
  public ConsumerCallbackResult flushCallQueue(long curTime)
  {
    ConsumerCallbackResult result = ConsumerCallbackResult.SUCCESS;
    if (0 >= curTime) curTime = System.nanoTime();

    TimestampedFuture<ConsumerCallbackResult> top = null;
    while (_submittedCalls.size() > 0)
    {
      top = _submittedCalls.peek();
      ConsumerCallbackResult topResult = null;
      Future<ConsumerCallbackResult> topFuture = top.getFuture();

      if (!topFuture.isDone())
      {
        if (0 >= curTime) curTime = System.nanoTime();
        long calcTimeout =  getEstimatedTimeout(_timeBudgetNanos, curTime,top);
        long timeoutNanos = _timeBudgetNanos > 0 ? ( calcTimeout > 0 ? calcTimeout : 0) : -1;
        topResult = getCallResult(topFuture, top.getCallType(), timeoutNanos);
        curTime = -1;
      }

      if (topFuture.isDone() && null == topResult) topResult = getCallResult(topFuture, top.getCallType(), -1);
      if (null == topResult) topResult = ConsumerCallbackResult.ERROR;

      result = ConsumerCallbackResult.max(result, topResult);
      if (ConsumerCallbackResult.isFailure(result))
      {
        _log.error("error detected; cancelling all " + _submittedCalls.size() + " outstanding callbacks");
        cancelCalls();
      }

      if (topFuture.isDone() && result != ConsumerCallbackResult.ERROR)
      {
        boolean debugEnabled = _log.isDebugEnabled();
        if (top.getCallType().equals("StartSourceCallable"))
        {
          long runTime = top.getCallable().getNanoRunTime() / DbusConstants.NUM_NSECS_IN_MSEC;
          if (debugEnabled)
          {
            StartSourceCallable tf = (StartSourceCallable) top.getCallable();
            _log.debug("StartSourceCallable time taken for source " + tf.getSource() + " = " + runTime);
          }
        }
        else if (top.getCallType().equals("StartDataEventSequenceCallable"))
        {
          long runTime = top.getCallable().getNanoRunTime() / DbusConstants.NUM_NSECS_IN_MSEC;
          if (debugEnabled)
          {
            StartDataEventSequenceCallable tf = (StartDataEventSequenceCallable) top.getCallable();
            _log.debug("StartDataEventSequenceCallable time taken for source " + tf.getSCN() + " = " + runTime);
          }
        }
      }

      dequeueTopFuture(result);
    }

    return result;
  }

  @Override
  public ConsumerCallbackResult onCheckpoint(SCN checkpointScn)
  {
    long curNanos = System.nanoTime();
    for (DatabusV2ConsumerRegistration consumerReg: _registrations)
    {
      for (DatabusCombinedConsumer consumer: consumerReg.getConsumers())
      {
        ConsumerCallable<ConsumerCallbackResult> checkpointCallable =
            _callbackFactory.createCheckpointCallable(curNanos, checkpointScn, consumer, true);
        _currentBatch.add(checkpointCallable);
        if (_consumerStats != null) _consumerStats.registerEventsReceived(1)// really "callbacks received"
      }
    }
    if (_loggingConsumer != null)
    {
      ConsumerCallable<ConsumerCallbackResult> checkpointCallable =
          _callbackFactory.createCheckpointCallable(curNanos, checkpointScn, _loggingConsumer, false);
      _currentBatch.add(checkpointCallable);
    }
    if (_log.isDebugEnabled())
    {
      long endNanos = System.nanoTime();
      _log.debug("Time spent in databus clientlib by onCheckpoint = " +
                (endNanos - curNanos) / DbusConstants.NUM_NSECS_IN_MSEC + "ms");
    }
    return submitBatch(curNanos, true, true);
  }

  @Override
  public ConsumerCallbackResult onDataEvent(DbusEvent e, DbusEventDecoder eventDecoder)
  {
    boolean debugEnabled = _log.isDebugEnabled();

    long curNanos = System.nanoTime();
    if (null == _sourceMap)
    {
      _log.error("No sources map specified");
      if (_consumerStats != null) _consumerStats.registerSrcErrors();
      return ConsumerCallbackResult.ERROR;
    }

    long srcid = e.srcId();
    short lPartitionId = e.logicalPartitionId();
    IdNamePair eventSource = _sourceMap.get(srcid);
    if (null == eventSource)
    {
      _log.error("Unknown source");
      if (_consumerStats != null) _consumerStats.registerSrcErrors();
      return ConsumerCallbackResult.ERROR;
    }

    for (DatabusV2ConsumerRegistration reg: _registrations)
    {
      DatabusSubscription eventSourceName = DatabusSubscription.createSubscription(eventSource, lPartitionId);
      if (debugEnabled) _log.debug("event source=" + eventSource + " lpart=" + lPartitionId);
      if (reg.checkSourceSubscription(eventSourceName))
      {

        if (debugEnabled) _log.debug("consumer matches:" + reg.getConsumer());
        ConsumerCallable<ConsumerCallbackResult> dataEventCallable =
            _callbackFactory.createDataEventCallable(curNanos, e, eventDecoder, reg.getConsumer(), true);
        _currentBatch.add(dataEventCallable);
        if (_consumerStats != null) _consumerStats.registerDataEventReceived(e);
        if (_unifiedClientStats != null) _unifiedClientStats.registerDataEventReceived(e);
      }
    }
    if (_loggingConsumer != null)
    {
      ConsumerCallable<ConsumerCallbackResult> dataEventCallable =
          _callbackFactory.createDataEventCallable(curNanos, e, eventDecoder, _loggingConsumer, false);
      _currentBatch.add(dataEventCallable);
    }
    if (debugEnabled)
    {
      long endNanos = System.nanoTime();
      _log.debug("Time spent in databus clientlib by onDataEvent = " +
                (endNanos - curNanos) / DbusConstants.NUM_NSECS_IN_MSEC + "ms");
    }

    return submitBatch(curNanos, false, false);
  }

  @Override
  public ConsumerCallbackResult onEndDataEventSequence(SCN endScn)
  {
    long curNanos = System.nanoTime();
    for (DatabusV2ConsumerRegistration consumerReg: _registrations)
    {
      for (DatabusCombinedConsumer consumer: consumerReg.getConsumers())
      {
        ConsumerCallable<ConsumerCallbackResult> endWindowCallable =
            _callbackFactory.createEndDataEventSequenceCallable(curNanos, endScn, consumer, true);
        _currentBatch.add(endWindowCallable);
        if (_consumerStats != null) _consumerStats.registerSystemEventReceived();
      }
    }
    if (_loggingConsumer != null)
    {
      ConsumerCallable<ConsumerCallbackResult> endWindowCallable =
          _callbackFactory.createEndDataEventSequenceCallable(curNanos, endScn, _loggingConsumer, false);
      _currentBatch.add(endWindowCallable);
    }
    if (_log.isDebugEnabled())
    {
      long endNanos = System.nanoTime();
      _log.debug("Time spent in databus clientlib by onEndDataEventSequence = " +
                (endNanos - curNanos) / DbusConstants.NUM_NSECS_IN_MSEC + "ms");
    }
    return submitBatch(curNanos, true, true);
  }

  @Override
  public ConsumerCallbackResult onEndSource(String source, Schema sourceSchema)
  {
    long curNanos = System.nanoTime();
    for (DatabusV2ConsumerRegistration consumerReg: _registrations)
    {
      for (DatabusCombinedConsumer consumer: consumerReg.getConsumers())
      {
        ConsumerCallable<ConsumerCallbackResult> endSourceCallable =
            _callbackFactory.createEndSourceCallable(curNanos, source, sourceSchema, consumer, true);
        _currentBatch.add(endSourceCallable);
        if (_consumerStats != null) _consumerStats.registerEventsReceived(1);
      }
    }
    if (_loggingConsumer != null)
    {
      ConsumerCallable<ConsumerCallbackResult> endSourceCallable =
          _callbackFactory.createEndSourceCallable(curNanos, source, sourceSchema, _loggingConsumer, false);
      _currentBatch.add(endSourceCallable);
    }
    if (_log.isDebugEnabled())
    {
      long endNanos = System.nanoTime();
      _log.debug("Time spent in databus clientlib by onEndSource = " +
                (endNanos - curNanos) / DbusConstants.NUM_NSECS_IN_MSEC + "ms");
    }
    return submitBatch(curNanos, true, true);
  }

  @Override
  public ConsumerCallbackResult onRollback(SCN startScn)
  {
    long curNanos = System.nanoTime();
    for (DatabusV2ConsumerRegistration consumerReg: _registrations)
    {
      for (DatabusCombinedConsumer consumer: consumerReg.getConsumers())
      {
        ConsumerCallable<ConsumerCallbackResult> rollbackCallable =
            _callbackFactory.createRollbackCallable(curNanos, startScn, consumer, true);
        _currentBatch.add(rollbackCallable);
        if (_consumerStats != null) _consumerStats.registerEventsReceived(1);
      }
    }
    if (_loggingConsumer != null)
    {
      ConsumerCallable<ConsumerCallbackResult> rollbackCallable =
          _callbackFactory.createRollbackCallable(curNanos, startScn, _loggingConsumer, false);
      _currentBatch.add(rollbackCallable);
    }
    if (_log.isDebugEnabled())
    {
      long endNanos = System.nanoTime();
      _log.debug("Time spent in databus clientlib by onRollback = " +
                (endNanos - curNanos) / DbusConstants.NUM_NSECS_IN_MSEC + "ms");
    }
    return submitBatch(curNanos, true, true);
  }

  @Override
  public ConsumerCallbackResult onStartDataEventSequence(SCN startScn)
  {
    long curNanos = System.nanoTime();
    for (DatabusV2ConsumerRegistration consumerReg: _registrations)
    {
      for (DatabusCombinedConsumer consumer: consumerReg.getConsumers())
      {
        ConsumerCallable<ConsumerCallbackResult> startWindowCallable =
          _callbackFactory.createStartDataEventSequenceCallable(curNanos, startScn, consumer, true);
        _currentBatch.add(startWindowCallable);
        if (_consumerStats != null) _consumerStats.registerEventsReceived(1);
      }
    }
    if (_loggingConsumer != null)
    {
      ConsumerCallable<ConsumerCallbackResult> startWindowCallable =
          _callbackFactory.createStartDataEventSequenceCallable(curNanos, startScn, _loggingConsumer, false);
      _currentBatch.add(startWindowCallable);
    }
    if (_log.isDebugEnabled())
    {
      long endNanos = System.nanoTime();
      _log.debug("Time spent in databus clientlib by onStartDataEventSequence = " +
                (endNanos - curNanos) / DbusConstants.NUM_NSECS_IN_MSEC + "ms");
    }

    return submitBatch(curNanos, true, true);
  }

  @Override
  public ConsumerCallbackResult onStartSource(String source, Schema sourceSchema)
  {
    long curNanos = System.nanoTime();
    for (DatabusV2ConsumerRegistration consumerReg: _registrations)
    {
      for (DatabusCombinedConsumer consumer: consumerReg.getConsumers())
      {
        ConsumerCallable<ConsumerCallbackResult> startSourceCallable =
          _callbackFactory.createStartSourceCallable(curNanos, source, sourceSchema, consumer, true);
        _currentBatch.add(startSourceCallable);
        if (_consumerStats != null) _consumerStats.registerEventsReceived(1);
      }
    }
    if (_loggingConsumer != null)
    {
      ConsumerCallable<ConsumerCallbackResult> startSourceCallable =
          _callbackFactory.createStartSourceCallable(curNanos, source, sourceSchema, _loggingConsumer, false);
      _currentBatch.add(startSourceCallable);
    }
    if (_log.isDebugEnabled())
    {
      long endNanos = System.nanoTime();
      _log.debug("Time spent in databus clientlib by onStartSource = " +
                (endNanos - curNanos) / DbusConstants.NUM_NSECS_IN_MSEC + "ms");
    }

    return submitBatch(curNanos, false, true);
  }

  @Override
  public ConsumerCallbackResult onStartConsumption()
  {
    long curNanos = System.nanoTime();
    for (DatabusV2ConsumerRegistration consumerReg: _registrations)
    {
      for (DatabusCombinedConsumer consumer: consumerReg.getConsumers())
      {
        ConsumerCallable<ConsumerCallbackResult> startConsumptionCallable =
            _callbackFactory.createStartConsumptionCallable(curNanos, consumer, true);
        _currentBatch.add(startConsumptionCallable);
        if (_consumerStats != null) _consumerStats.registerEventsReceived(1);
      }
    }
    if (_loggingConsumer != null)
    {
      ConsumerCallable<ConsumerCallbackResult> startConsumptionCallable =
          _callbackFactory.createStartConsumptionCallable(curNanos, _loggingConsumer, false);
      _currentBatch.add(startConsumptionCallable);
    }
    if (_log.isDebugEnabled())
    {
      long endNanos = System.nanoTime();
      _log.debug("Time spent in databus clientlib by onStartConsumption = " +
                (endNanos - curNanos) / DbusConstants.NUM_NSECS_IN_MSEC + "ms");
    }
    return submitBatch(curNanos, false, true);
  }

  @Override
  public ConsumerCallbackResult onStopConsumption()
  {
    long curNanos = System.nanoTime();
    for (DatabusV2ConsumerRegistration consumerReg: _registrations)
    {
      for (DatabusCombinedConsumer consumer: consumerReg.getConsumers())
      {
        ConsumerCallable<ConsumerCallbackResult> endConsumptionCallable =
          _callbackFactory.createEndConsumptionCallable(curNanos, consumer, true);
        _currentBatch.add(endConsumptionCallable);
        if (_consumerStats != null) _consumerStats.registerEventsReceived(1);

      }
    }
    if (_loggingConsumer != null)
    {
      ConsumerCallable<ConsumerCallbackResult> endConsumptionCallable =
          _callbackFactory.createEndConsumptionCallable(curNanos, _loggingConsumer, false);
      _currentBatch.add(endConsumptionCallable);
    }
    if (_log.isDebugEnabled())
    {
      long endNanos = System.nanoTime();
      _log.debug("Time spent in databus clientlib by onStopConsumption = " +
                (endNanos - curNanos) / DbusConstants.NUM_NSECS_IN_MSEC + "ms");
    }
    return submitBatch(curNanos, true, true);
  }

  public void setSourceMap(Map<Long, IdNamePair> sourceMap)
  {
    _sourceMap = sourceMap;
  }

  public Map<Long, IdNamePair> getSourceMap()
  {
    return _sourceMap;
  }

  @Override
  public ConsumerCallbackResult onError(Throwable err)
  {
    long curNanos = System.nanoTime();
    for (DatabusV2ConsumerRegistration consumerReg: _registrations)
    {
      for (DatabusCombinedConsumer consumer: consumerReg.getConsumers())
      {
        ConsumerCallable<ConsumerCallbackResult> onErrorCallable =
          _callbackFactory.createOnErrorCallable(curNanos, err, consumer, true);
        _currentBatch.add(onErrorCallable);
        if (_consumerStats != null) _consumerStats.registerErrorEventsProcessed(1)// FIXME:  bug?  "processed" usually means consumer callback has completed; registerErrorEventsProcessed() normally called only if consumer callback returns ERROR:  why no registerErrorEventsReceived() call here?
      }
    }
    if (_loggingConsumer != null)
    {
      ConsumerCallable<ConsumerCallbackResult> onErrorCallable =
          _callbackFactory.createOnErrorCallable(curNanos, err, _loggingConsumer, false);
      _currentBatch.add(onErrorCallable);
    }
    if (_log.isDebugEnabled())
    {
      long endNanos = System.nanoTime();
      _log.debug("Time spent in databus clientlib by onError = " +
                (endNanos - curNanos) / DbusConstants.NUM_NSECS_IN_MSEC + "ms");
    }
    return submitBatch(curNanos, true, true);
  }

  public ConsumerCallbackStats getStats()
  {
      return _consumerStats;
  }

  static class TimestampedFuture<T>
  {
    private final Future<T> _future;
    private final String _callType;
    private final long _callNum;
    private final ConsumerCallable<T> _callable;

    public TimestampedFuture(ConsumerCallable<T> callable, Future<T> future, String callType,
                             long callNum)
    {
      super();
      _future = future;
      _callType = callType;
      _callNum = callNum;
      _callable = callable;
    }

    public Future<T> getFuture()
    {
      return _future;
    }
    public long getTimestamp()
    {
      return _callable.getCreationTime();
    }

    public long getCallNum()
    {
      return _callNum;
    }

    public String getCallType()
    {
      return _callType;
    }

    public ConsumerCallable<T> getCallable()
    {
      return _callable;
    }
  }

  static class TimestampedFutureComparator<T> implements Comparator<TimestampedFuture<T>>, Serializable
  {
    private static final long serialVersionUID = 1L;

    @Override
    public int compare(TimestampedFuture<T> o1, TimestampedFuture<T> o2)
    {
      return (int)(o1.getTimestamp() - o2.getTimestamp());
    }
  }

  public void removeRegistration(DatabusV2ConsumerRegistration reg)
  {
    _registrations.remove(reg);
  }

  protected long getEstimatedTimeout(long timeBudget,
                                     long curTime,
                                     TimestampedFuture<ConsumerCallbackResult> top)
  {
    return (timeBudget - (curTime - top.getTimestamp()));
  }
}
TOP

Related Classes of com.linkedin.databus.client.consumer.MultiConsumerCallback$TimestampedFutureComparator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.