Package com.linkedin.databus.client

Source Code of com.linkedin.databus.client.DispatcherState

package com.linkedin.databus.client;
/*
*
* 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.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

import com.linkedin.databus.client.pub.SCN;
import com.linkedin.databus.core.Checkpoint;
import com.linkedin.databus.core.DbusEventBuffer;
import com.linkedin.databus.core.DbusLogAccumulator;
import com.linkedin.databus.core.util.IdNamePair;
import com.linkedin.databus2.core.container.request.RegisterResponseEntry;
import com.linkedin.databus2.core.container.request.RegisterResponseMetadataEntry;
import com.linkedin.databus2.schemas.SchemaId;
import com.linkedin.databus2.schemas.SchemaRegistryService;
import com.linkedin.databus2.schemas.VersionedSchemaSet;

public class DispatcherState
{
  public static final String MODULE = DispatcherState.class.getName();
  public static final Logger LOG = Logger.getLogger(MODULE);

  public enum StateId
  {
    //Initial state when is the dispatcher is started
    INITIAL,
    //Start reading from event buffer and dispatch events.
    START_DISPATCH_EVENTS,
    //First event of a new window (end of window for the previous window has been seen)
    EXPECT_EVENT_WINDOW,
    //Start of a window (which will be followed by data events)
    START_STREAM_EVENT_WINDOW,
    //End of events for a source within a window
    START_STREAM_SOURCE,
    //Beginning of data events to be streamed
    EXPECT_STREAM_DATA_EVENTS,
    //End of events for a source within a window (which maybe followed by more sources)
    END_STREAM_SOURCE,
    //End of a window
    END_STREAM_EVENT_WINDOW,
    //Rollback is triggered (after error in the consumer)
    ROLLBACK,
    //After rollback, events are replayed to the consumer
    REPLAY_DATA_EVENTS,
    //Not used (???)
    STOP_DISPATCH_EVENTS,
    //Shutdown the dispatcher
    CLOSED
  }

  private StateId _stateId;


  //START_DISPATCH_EVENTS
  private final Map<Long, IdNamePair> _sources = new HashMap<Long, IdNamePair>();

  //payload schemas
  private static final VersionedSchemaSet _schemaSet = new VersionedSchemaSet(true);
  //metadata schemas
  private static final VersionedSchemaSet _metadataSchemasSet = new VersionedSchemaSet();



  private DbusEventBuffer.DbusEventIterator _eventsIterator;
  private DbusEventBuffer.DbusEventIterator _lastSuccessfulIterator;
  // Looks like _payloadSchemaMap is a member variable purely for testing purposes. Keeping it thus can
  // introduce bugs like DDSDBUS-3271. Need to remove the member variable.
  private final Map<Long, List<RegisterResponseEntry>> _payloadSchemaMap = new HashMap<Long, List<RegisterResponseEntry>>();
  private DbusEventBuffer _buffer;

  //EXPECT_EVENT_WINDOW extends START_DISPATCH_EVENTS

  //START_STREAM_EVENT_WINDOW extends DISPATCH_EVENTS
  private volatile SCN _startWinScn;
  private boolean _eventsSeen;

  //START_STREAM_SOURCE extends START_STREAM_EVENT_WINDOW
  private IdNamePair _currentSource;
  private Schema _currentSourceSchema;

  //EXPECT_STREAM_DATA_EVENTS extends START_STREAM_SOURCE

  //END_STREAM_SOURCE extends START_STREAM_SOURCE
  private volatile SCN _endWinScn;

  //END_STREAM_EVENT_WINDOW extends START_STREAM_EVENT_WINDOW

  //CHECKPOINT extends END_STREAM_EVENT_WINDOW
  private Checkpoint _lastSuccessfulCheckpoint;
  private SCN _lastSuccessfulScn;

  //ROLLBACK extends DISPATCH_EVENTS

  //REPLAY_DATA_EVENTS extends ROLLBACK

  //STOP_DISPATCH_EVENTS

  private DbusEventAvroDecoder _eventDecoder;


  private boolean _scnRegress = false;

  private DispatcherState()
  {
    super();
    _stateId = StateId.INITIAL;
  }

  private DispatcherState(DbusEventBuffer buffer)
  {
    super();
    _stateId = StateId.INITIAL;
    _buffer = buffer;
  }

  public static DispatcherState create()
  {
    return new DispatcherState();
  }

  public static DispatcherState create(DbusEventBuffer eventBuffer, String iteratorName)
  {
    DispatcherState result = new DispatcherState(eventBuffer);
    result.createEventsIterator(iteratorName);
    return result;
  }

  private void setLastSuccessfulIterator(DbusEventBuffer.DbusEventIterator newValue)
  {
    final boolean isDebugEnabled = LOG.isDebugEnabled();
    if (isDebugEnabled)
    {
      DbusLogAccumulator.addLog("Changing _lastSuccessfulIterator from: " + _lastSuccessfulIterator, LOG);
    }
    if (null != _lastSuccessfulIterator)
    {
      _lastSuccessfulIterator.close();
    }
    if (null == newValue)
    {
      _lastSuccessfulIterator = null;
    }
    else
    {
      _lastSuccessfulIterator = newValue.copy(_lastSuccessfulIterator, newValue.getIdentifier() + ".save");
    }
    if (isDebugEnabled)
    {
      DbusLogAccumulator.addLog("Changing _lastSuccessfulIterator to: " + _lastSuccessfulIterator, LOG);
    }
  }

  public DispatcherState switchToStartDispatchEvents()
  {
    _stateId = StateId.START_DISPATCH_EVENTS;
    return this;
  }

  private void createEventsIterator(String iteratorName)
  {
    if (null == _eventsIterator)
    {
      _stateId = StateId.START_DISPATCH_EVENTS;
      _lastSuccessfulCheckpoint = null;
      _lastSuccessfulScn = null;
      resetSourceInfo();
      _eventsIterator = _buffer.acquireIterator(iteratorName);
      LOG.info("start dispatch from: " + _eventsIterator);
      setLastSuccessfulIterator(_eventsIterator);
    }
  }

  private void refreshSchemas(List<RegisterResponseMetadataEntry> metadataSchemaList)
  {
    final boolean isDebugEnabled = LOG.isDebugEnabled();
    try
    {
      for (Map.Entry<Long, List<RegisterResponseEntry>> e: _payloadSchemaMap.entrySet())
      {
        for (RegisterResponseEntry r : e.getValue())
        {
          final long id = r.getId();
          String schemaName = null;
          if (_sources.containsKey(id))
          {
            schemaName = _sources.get(r.getId()).getName();
          }
          else
          {
            LOG.error("Obtained a RegisterResponseEntry with schema that has no sourceId set. id = " + id);
            continue;
          }
          String schema = r.getSchema();
          if (_schemaSet.add(schemaName, r.getVersion(), schema))
          {
            LOG.info("Registering schema name=" + schemaName + " id=" + e.getKey().toString() +
                " version=" + r.getVersion());

            if (isDebugEnabled)
            {
              String msg = "Registering schema name=" + schemaName + " id=" + e.getKey().toString() +
                  " version=" + r.getVersion() + ": " + schema;
              DbusLogAccumulator.addLog(msg, LOG);
            }
          }
          else
          {
            if (isDebugEnabled)
            {
              String msg = "Schema already known: " + schemaName + " version " +  r.getId();
              DbusLogAccumulator.addLog(msg, LOG);
            }
          }
        }
      }

      //Refresh metadata schema map
      if ((metadataSchemaList != null) && !metadataSchemaList.isEmpty())
      {
        for (RegisterResponseMetadataEntry e: metadataSchemaList)
        {
          SchemaId id = new SchemaId(e.getCrc32());
          if (_metadataSchemasSet.add(SchemaRegistryService.DEFAULT_METADATA_SCHEMA_SOURCE,e.getVersion(),id,e.getSchema()))
          {
            LOG.info("Added metadata schema version " + e.getVersion() + ",schemaID=0x" + id);
          }
          else
          {
            if (isDebugEnabled)
            {
              String msg = "Metadata schema version " + e.getVersion() + ",schemaId=0x" + id + " already exists";
              DbusLogAccumulator.addLog(msg, LOG);
            }
          }
        }
      }
      else
      {
        if (isDebugEnabled)
        {
          String msg = "Metadata schema is empty";
          DbusLogAccumulator.addLog(msg, LOG);
        }
      }

      _eventDecoder = new DbusEventAvroDecoder(_schemaSet,_metadataSchemasSet);
    }
    catch (Exception e)
    {
      LOG.error("Error adding schema", e);
    }
  }

  public void resetIterators()
  {
    if (null != _lastSuccessfulIterator)
    {
      setLastSuccessfulIterator(null);
      _lastSuccessfulScn = null;
      _lastSuccessfulCheckpoint = null;
    }

    if (null != _eventsIterator)
    {
      DbusEventBuffer eventBuffer = _eventsIterator.getEventBuffer();
      String iteratorName = _eventsIterator.getIdentifier();
      _eventsIterator.close();
      _eventsIterator = eventBuffer.acquireIterator(iteratorName);
      if (LOG.isDebugEnabled())
      {
        String msg = "Reset event iterator to: " + _eventsIterator;
        DbusLogAccumulator.addLog(msg, LOG);
      }
      resetSourceInfo();
    }
  }

  public void switchToExpectEventWindow()
  {
    _stateId = StateId.EXPECT_EVENT_WINDOW;
  }

  public DispatcherState switchToStopDispatch()
  {
    _stateId = StateId.STOP_DISPATCH_EVENTS;
    setEventsIterator(null);
    return this;
  }

  public DispatcherState switchToClosed()
  {
    _stateId = StateId.CLOSED;
    setLastSuccessfulIterator(null);
    setEventsIterator(null);
    return this;
  }

  public synchronized void switchToStartStreamEventWindow(SCN startWinScn)
  {
    _stateId = StateId.START_STREAM_EVENT_WINDOW;
    _startWinScn = startWinScn;
    _eventsSeen = true;
    resetSourceInfo();
  }

  public synchronized void switchToEndStreamEventWindow(SCN endWinScn)
  {
    _stateId = StateId.END_STREAM_EVENT_WINDOW;
    _endWinScn = endWinScn;
    _eventsSeen = false;
  }

  public void switchToStartStreamSource(IdNamePair source, Schema sourceSchema)
  {
    _stateId = StateId.START_STREAM_SOURCE;
    _currentSource = source;
    _currentSourceSchema = sourceSchema;
  }

  public void switchToEndStreamSource()
  {
    _stateId = StateId.END_STREAM_SOURCE;
  }

  public void switchToExpectStreamDataEvents()
  {
    _stateId = StateId.EXPECT_STREAM_DATA_EVENTS;
  }

  public void storeCheckpoint(Checkpoint cp, SCN scn)
  {
    _lastSuccessfulCheckpoint = cp;
    _lastSuccessfulScn = scn;
    setLastSuccessfulIterator(_eventsIterator);
  }

  public void switchToRollback()
  {
    _stateId = StateId.ROLLBACK;
    _eventsSeen = false;
  }

  private void setEventsIterator(DbusEventBuffer.DbusEventIterator newValue)
  {
    String iterName = null == newValue ? "dispatcher iterator" :
      newValue.getIdentifier();
    if (null != _eventsIterator)
    {
      iterName = _eventsIterator.getIdentifier();
      if (LOG.isDebugEnabled())
      {
        String msg = "Closing dispatcher iterator: " + _eventsIterator;
        DbusLogAccumulator.addLog(msg, LOG);
      }
      _eventsIterator.close();
    }
    if (null == newValue)
    {
      _eventsIterator = null;
      if (LOG.isDebugEnabled())
      {
        String msg = "Dispatcher iterator set to null";
        DbusLogAccumulator.addLog(msg, LOG);
      }
    }
    else
    {
      _eventsIterator = newValue.copy(_eventsIterator, iterName);
      if (LOG.isDebugEnabled())
      {
        String msg = "New dispatcher iterator: " + _eventsIterator;
        DbusLogAccumulator.addLog(msg, LOG);
      }
    }
  }

  public void switchToReplayDataEvents()
  {
    _stateId = StateId.REPLAY_DATA_EVENTS;
    resetSourceInfo();
    setEventsIterator(_lastSuccessfulIterator);
  }

  public void resetSourceInfo()
  {
    _currentSource = null;
    _currentSourceSchema = null;
  }

  public StateId getStateId()
  {
    return _stateId;
  }

  public DbusEventBuffer.DbusEventIterator getEventsIterator()
  {
    return _eventsIterator;
  }

  public Map<Long, IdNamePair> getSources()
  {
    return _sources;
  }

  public DbusEventAvroDecoder getEventDecoder()
  {
    return _eventDecoder;
  }

  public synchronized SCN getStartWinScn()
  {
    return _startWinScn;
  }

  public IdNamePair getCurrentSource()
  {
    return _currentSource;
  }

  public Schema getCurrentSourceSchema()
  {
    return _currentSourceSchema;
  }

  public synchronized SCN getEndWinScn()
  {
    return _endWinScn;
  }

  public Checkpoint getLastSuccessfulCheckpoint()
  {
    return _lastSuccessfulCheckpoint;
  }

  public VersionedSchemaSet getSchemaSet()
  {
    return _schemaSet;
  }

  public SCN getLastSuccessfulScn()
  {
    return _lastSuccessfulScn;
  }

  public DbusEventBuffer.DbusEventIterator getLastSuccessfulIterator()
  {
    return _lastSuccessfulIterator;
  }

  @Override
  public String toString()
  {
    return "DispatcherState:" + _stateId.toString();
  }

  public Map<Long, List<RegisterResponseEntry>> getSchemaMap()
  {
    return _payloadSchemaMap;
  }

  public void removeEvents()
  {
    DbusEventBuffer.DbusEventIterator iter = getEventsIterator();
    if (!iter.equivalent(_lastSuccessfulIterator))
    {
      if (_lastSuccessfulIterator == null)
      {
        LOG.warn("Last Successful Iterator was null. Rollback will not be possible!");
      }
      else
      {
        LOG.info("Invalidating last successful iterator " + "last = " +
            _lastSuccessfulIterator +  " this iterator= " + iter);
        setLastSuccessfulIterator(null);
      }
    }
    iter.remove();
  }

  public boolean isSCNRegress()
  {
    return _scnRegress;
  }

  public void setSCNRegress(boolean scnRegress)
  {
    _scnRegress = scnRegress;
  }

  public boolean isEventsSeen()
  {
    return _eventsSeen;
  }

  public void setEventsSeen(boolean hasSeenDataEvents)
  {
    _eventsSeen = hasSeenDataEvents;
  }

  protected DispatcherState addSources(Collection<IdNamePair> sources)
  {
    for (IdNamePair source: sources)
    {
      _sources.put(source.getId(), source);
    }

    return this;
  }

  protected DispatcherState addSchemas(Map<Long, List<RegisterResponseEntry>> schemaMap)
  {
    return addSchemas(schemaMap,null);
  }


  protected DispatcherState addSchemas(Map<Long, List<RegisterResponseEntry>> schemaMap,
      List<RegisterResponseMetadataEntry> metadataSchemaList)
  {
    _payloadSchemaMap.putAll(schemaMap);
    refreshSchemas(metadataSchemaList);
    return this;
  }
}
TOP

Related Classes of com.linkedin.databus.client.DispatcherState

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.