Package com.linkedin.databus.bootstrap.utils

Source Code of com.linkedin.databus.bootstrap.utils.BootstrapAuditMain

package com.linkedin.databus.bootstrap.utils;

/*
* 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.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.avro.Schema;
import org.apache.avro.Schema.Field;
import org.apache.avro.Schema.Type;
import org.apache.avro.generic.GenericRecord;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import com.linkedin.databus.bootstrap.utils.BootstrapAuditTableReader.ResultSetEntry;
import com.linkedin.databus.bootstrap.utils.BootstrapSrcDBEventReader.PrimaryKeyTxn;
import com.linkedin.databus.client.DbusEventAvroDecoder;
import com.linkedin.databus.core.DbusEventKey;
import com.linkedin.databus.core.util.StringUtils;
import com.linkedin.databus2.producers.db.OracleTriggerMonitoredSourceInfo;
import com.linkedin.databus2.relay.OracleJarUtils;
import com.linkedin.databus2.schemas.FileSystemSchemaRegistryService;
import com.linkedin.databus2.schemas.SchemaRegistryService;
import com.linkedin.databus2.schemas.VersionedSchema;
import com.linkedin.databus2.schemas.VersionedSchemaSet;
import com.linkedin.databus2.schemas.utils.SchemaHelper;
import com.linkedin.databus2.util.DBHelper;

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

  static
  {
    BasicConfigurator.configure();
    Logger.getRootLogger().setLevel(Level.INFO);
  }

  /**
   * @param args
   */
  public static void main(String[] args) throws Exception
  {
    BootstrapSeederMain.init(args);

    BootstrapSeederMain.StaticConfig staticConfig = BootstrapSeederMain
        .getStaticConfig();

    int interval = staticConfig.getController().getCommitInterval();

    int sourceChunkSize = staticConfig.getController().getNumRowsPerQuery();

    List<OracleTriggerMonitoredSourceInfo> sources = BootstrapSeederMain
        .getSources();
    BootstrapDBSeeder seeder = BootstrapSeederMain.getSeeder();
    BootstrapSrcDBEventReader seedController = BootstrapSeederMain.getReader();

    Map<String, String> pKeyNameMap = seedController.getpKeyNameMap();
    Map<String, DbusEventKey.KeyType> pKeyTypeMap = seedController
        .getpKeyTypeMap();

    for (OracleTriggerMonitoredSourceInfo source : sources)
    {
      short srcId = source.getSourceId();

      new ConcurrentHashMap<Long, ResultSetEntry>();
      OracleTableReader oracleReader = null;
      MySQLTableReader mySQLReader = null;

      try
      {

        SchemaRegistryService schemaRegistry = FileSystemSchemaRegistryService
            .build(staticConfig.getSchemaRegistry().getFileSystem());
        Map<Short, String> schemaSet = schemaRegistry
            .fetchAllSchemaVersionsBySourceName(source.getSourceName());
        VersionedSchemaSet vSchemaSet = new VersionedSchemaSet();
        Iterator<Map.Entry<Short, String>> it = schemaSet.entrySet().iterator();
        while (it.hasNext())
        {
          Map.Entry<Short, String> pairs = it.next();
          Schema s = Schema.parse(pairs.getValue());
          VersionedSchema vs = new VersionedSchema(s.getFullName(),
              pairs.getKey(), s, null);
          vSchemaSet.add(vs);
        }

        /* Try and identify the schema key */
        VersionedSchema vschema = schemaRegistry
            .fetchLatestVersionedSchemaBySourceName(source.getSourceName());
        Schema schema = Schema.parse(vschema.getSchema().toString());
        LOG.info("Schema =" + vschema.getSchema() + "version="
            + vschema.getVersion() + " name=" + vschema.getSchemaBaseName());

        /* Determine type of field txn */
        Field txnFieldType = schema.getField("txn");
        if (txnFieldType == null)
        {
          throw new Exception(
              "Unable to find field called 'txn'. Cannot proceeed\n");
        }
        Type txnType = SchemaHelper.getAnyType(txnFieldType);

        /*
         * Determine primary key of schema. This is assumed to be invariant
         * across versions
         */
        String keyOverrideName = SchemaHelper.getMetaField(schema, "pk");
        String keyColumnName = "key";
        if (null != keyOverrideName)
        {
          keyColumnName = keyOverrideName;
        }
        Field pkeyField = schema.getField(keyColumnName);
        if (null == pkeyField)
        {
          keyColumnName = "id";
          pkeyField = schema.getField("id");
        }
        if (null == pkeyField)
        {
          throw new Exception(
              "Unable to get the primary key for schema. Schema is :" + schema);
        }

        DbusEventAvroDecoder decoder = new DbusEventAvroDecoder(vSchemaSet);

        BootstrapAuditTester auditor = new BootstrapAuditTester(schema, BootstrapSrcDBEventReader.getTableName(source));
        List<BootstrapAuditTester> auditors = new ArrayList<BootstrapAuditTester>();
        auditors.add(auditor);

        oracleReader = new OracleTableReader(BootstrapSeederMain.getDataStore()
            .getConnection(), BootstrapSrcDBEventReader.getTableName(source),
            pkeyField, SchemaHelper.getMetaField(pkeyField, "dbFieldName"),
            SchemaHelper.getAnyType(pkeyField), sourceChunkSize,
            seedController.getPKIndex(source),
            seedController.getQueryHint(source));

        mySQLReader = new MySQLTableReader(seeder.getConnection(),
            seeder.getTableName(srcId), pkeyField, "id", // THis is the primary
                                                         // key always for
                                                         // bootstrapDB
            SchemaHelper.getAnyType(pkeyField), interval);

        double samplePct = BootstrapSeederMain.getValidationSamplePct();

        TableComparator comparator = new TableComparator(oracleReader,
            mySQLReader, auditor, decoder, interval, pKeyNameMap.get(source
                .getEventView()), pKeyTypeMap.get(source.getEventView()),
            txnType, samplePct);

        boolean success = false;
        if (BootstrapSeederMain.getValidationType().equals("point"))
        {
          success = comparator.compareRecordsPoint();
        }
        else if (BootstrapSeederMain.getValidationType().equals("pointBs"))
        {
          success = comparator.compareRecordsPointBs();
        }
        else
        {
          success = comparator.compareRecordsNew();
        }

        if (success)
          LOG.info("Audit completed successfully");
        else
          LOG.error("Audit FAILED !!! ");
      }
      catch (Exception ex)
      {
        LOG.error("Caught an exception ex", ex);
        throw ex;
      }
      finally
      {
        if (null != oracleReader)
          oracleReader.close();
      }
    }
    DBHelper.close(seeder.getConnection());
  }

  public static class AuditStats implements Runnable
  {

    private long _numProcessed = 0;
    private long _numKeyEqual = 0;
    private long _numKeyAbsentInBootstrap = 0;
    private long _numKeyAbsentInOracle = 0;
    private long _numDataEqual = 0;
    private long _numOlderTxnInOracle = 0;
    private long _numOlderTxnInBootstrap = 0;

    private boolean _shutdown = false;
    final private int _intervalInSec;
    private long _numError = 0;

    public AuditStats()
    {
      this(30);
    }

    public AuditStats(int intervalSec)
    {
      _intervalInSec = intervalSec;
    }

    @Override
    public void run()
    {
      while (!_shutdown)
      {
        print();
        try
        {
          Thread.sleep(_intervalInSec * 1000);
        }
        catch (InterruptedException e)
        {
          _shutdown = true;
        }
      }
      print();
    }

    public void print()
    {
      LOG.info("AuditStats\n" + this);
    }

    @Override
    public String toString()
    {
      StringBuilder s = new StringBuilder(512);
      s.append(" numProcessed=").append(_numProcessed).append(" numKeyEqual=")
          .append(_numKeyEqual).append(" numDataEqual=").append(_numDataEqual)
          .append(" numKeyAbsentInOracle=").append(_numKeyAbsentInOracle)
          .append(" numKeyAbsentInBootstrap=").append(_numKeyAbsentInBootstrap)
          .append(" numOlderTxnInOracle=").append(_numOlderTxnInOracle)
          .append(" numOlderTxnInBootstrap=").append(_numOlderTxnInBootstrap)
          .append(" numError=").append(_numError);
      return s.toString();
    }

    public synchronized void shutdown()
    {
      _shutdown = true;
    }

    public long getNumProcessed()
    {
      return _numProcessed;
    }

    public long getNumKeyEqual()
    {
      return _numKeyEqual;
    }

    public long getNumKeyAbsentInBootstrap()
    {
      return _numKeyAbsentInBootstrap;
    }

    public long getNumKeyAbsentInOracle()
    {
      return _numKeyAbsentInOracle;
    }

    public long getNumDataEqual()
    {
      return _numDataEqual;
    }

    public long getNumOlderTxnInOracle()
    {
      return _numOlderTxnInOracle;
    }

    public long getNumOlderTxnInBootstrap()
    {
      return _numOlderTxnInBootstrap;
    }

    public boolean isShutdown()
    {
      return _shutdown;
    }

    public int getIntervalInSec()
    {
      return _intervalInSec;
    }

    public long getNumError()
    {
      return _numError;
    }

    public synchronized void incNumProcessed()
    {
      _numProcessed++;
    }

    public synchronized void incNumnKeyAbsentInOracle()
    {
      _numKeyAbsentInOracle++;
    }

    public synchronized void incNumKeyAbsentInBootstrap()
    {
      _numKeyAbsentInBootstrap++;
    }

    public synchronized void incNumOlderTxnInBootstrap()
    {
      _numOlderTxnInBootstrap++;
    }

    public synchronized void incNumOlderTxnInOracle()
    {
      _numOlderTxnInOracle++;
    }

    public synchronized void incNumDataEqual()
    {
      _numDataEqual++;
    }

    public synchronized void incNumKeyEqual()
    {
      _numKeyEqual++;
    }

    public synchronized void incNumError()
    {
      _numError++;
    }

  }

  public static class TableComparator
  {
    private final OracleTableReader _srcReader;
    private final MySQLTableReader _destReader;
    private final DbusEventAvroDecoder _decoder;
    private final BootstrapAuditTester _auditor;
    private final int _interval;
    private final String _pKey;
    private final DbusEventKey.KeyType _pKeyType;
    private final Type _txnType;
    private final double _samplePct;
    private final Random _rand = new Random();

    public TableComparator(OracleTableReader srcReader,
        MySQLTableReader destReader, BootstrapAuditTester auditor,
        DbusEventAvroDecoder decoder, int interval, String pKey,
        DbusEventKey.KeyType pKeyType, Type txnType, double samplePct)
    {
      _srcReader = srcReader;
      _destReader = destReader;
      _decoder = decoder;
      _interval = interval;
      _auditor = auditor;
      _pKey = pKey;
      _pKeyType = pKeyType;
      _txnType = txnType;
      _samplePct = samplePct;
      LOG.info("Comparator: interval=" + _interval + " samplePct=" + _samplePct);
    }

    // called before deciding to compare
    private boolean shouldCompare()
    {
      if (_samplePct == 0)
      {
        return false;
      }
      else if (_samplePct == 100)
      {
        return true;
      }
      return (_samplePct > _rand.nextDouble() * 100.0);
    }

    public boolean compareRecordsPointBs() throws SQLException
    {
      AuditStats stats = new AuditStats();
      Thread statsThread = new Thread(stats);
      try
      {
        ResultSet srcRs = null;
        ResultSet destRs = null;
        /*
         * long srcNumRows = _srcReader.getNumRecords(_pKey); long destNumRows =
         * _destReader.getNumRecords("id");
         *
         * LOG.info("Current Number of Rows in Source DB :" + srcNumRows);
         * LOG.info("Current Number of Rows in Destination DB :" + destNumRows);
         */
        statsThread.start();

        String lastSrcKey = "0";
        boolean oracleDone = true;
        boolean done = false;
        while (!done)
        {

          // Read the next chunks from src and dest db's
          if (oracleDone)
          {
            done = true;
            DBHelper.close(srcRs);
            srcRs = _srcReader.getRecords(lastSrcKey);
          }

          oracleDone = !srcRs.next();
          done = done && oracleDone;
          if (!oracleDone)
          {
            /* For getting next row in boostrap db and oracle */
            /* The keys on which the query result set is ordered */
            lastSrcKey = getKey(srcRs);
            // read one record from BS

            if (!shouldCompare())
              continue;
            stats.incNumProcessed();
            DBHelper.close(destRs);
            destRs = _destReader.getRecord(lastSrcKey);

            boolean found = destRs.next();
            // Compare txn_id, key of both oracle and bs sources;
            // src_txn (oracle) , dst_txn(bootstrap) : destKey is the key field
            // in bs and srcKey is corresponding one in oracle
            if (found)
            {
              stats.incNumKeyEqual();
              /* For reading txnid, key which will form the basis of comparison */
              long srcTxnId = srcRs.getLong(2);
              long dstTxnId = getDestTxnId(destRs);

              // assumption: txnids are monotonically increasing
              if (srcTxnId == dstTxnId)
              {
                boolean result = _auditor
                    .compareRecord(srcRs, destRs, _decoder);
                if (result)
                {
                  stats.incNumDataEqual();
                }
                else
                {
                  LOG.error("Compare error: Key=" + lastSrcKey);
                }
              }
              else if (srcTxnId < dstTxnId)
              {
                stats.incNumOlderTxnInOracle();
              }
              else
              {
                // older txn in bootstrap;
                stats.incNumOlderTxnInBootstrap();
              }
            }
            else
            {
              LOG.info("Absent in bootstrap: " + lastSrcKey);
              // key present in oracle but not in bootstrap;
              stats.incNumKeyAbsentInBootstrap();
            }
          }

        }
        LOG.info("Done with audit- end of stream reached\n");
        stats.shutdown();
        statsThread.interrupt();
        statsThread.join();
        return stats.getNumProcessed() == stats.getNumDataEqual();
      }
      catch (SQLException e)
      {
        stats.shutdown();
        statsThread.interrupt();
        throw e;
      }
      catch (InterruptedException e)
      {

      }
      LOG.info("Done with audit- end of stream reached\n");
      return stats.getNumProcessed() == stats.getNumDataEqual();

    }

    public boolean compareRecordsPoint() throws SQLException
    {
      AuditStats stats = new AuditStats();
      Thread statsThread = new Thread(stats);
      try
      {
        ResultSet srcRs = null;
        ResultSet destRs = null;

        statsThread.start();

        long lastDestId = 0;
        boolean bootstrapDone = true;
        boolean done = false;
        while (!done)
        {

          if (bootstrapDone)
          {
            done = true;
            // batch sample; for uniform sampling set batch size (_interval) to
            // 1 .
            if (shouldCompare())
            {
              DBHelper.close(destRs);
              destRs = _destReader.getRecordsSequential(lastDestId);
            }
            else
            {
              // skip this batch
              done = false;
              lastDestId += _interval;
              continue;
            }
          }

          bootstrapDone = !destRs.next();

          done = done && bootstrapDone;
          if (!bootstrapDone)
          {
            // get next rowId
            lastDestId = destRs.getLong(1);
            /* For getting next row in boostrap db and oracle */
            String lastDestKey = destRs.getString(3);

            stats.incNumProcessed();

            // read that one record from Oracle
            DBHelper.close(srcRs);
            srcRs = _srcReader.getRecord(lastDestKey);
            boolean found = srcRs.next();

            if (found)
            {
              stats.incNumKeyEqual();
              /* For reading txnid, key which will form the basis of comparison */
              long srcTxnId = srcRs.getLong(2);
              long dstTxnId = getDestTxnId(destRs);
              if (dstTxnId != 0)
              {
                // assumption: txnids are monotonically increasing
                if (srcTxnId == dstTxnId)
                {
                  boolean result = _auditor.compareRecord(srcRs, destRs,
                      _decoder);
                  if (result)
                  {
                    stats.incNumDataEqual();
                  }
                  else
                  {
                    LOG.error("Compare error: Key=" + lastDestKey);
                  }
                }
                else if (srcTxnId < dstTxnId)
                {
                  // older txn in oracle - this cannot happen
                  stats.incNumOlderTxnInOracle();
                }
                else
                {
                  // older txn in bootstrap;
                  stats.incNumOlderTxnInBootstrap();
                }
              }
              else
              {
                stats.incNumError();
              }
            }
            else
            {
              // key present in bootstrap but not in oracle;
              stats.incNumnKeyAbsentInOracle();
            }
          }
        }
        LOG.info("Done with audit- end of stream reached\n");
        stats.shutdown();
        statsThread.interrupt();
        statsThread.join();
        return stats.getNumProcessed() == stats.getNumDataEqual();
      }
      catch (SQLException e)
      {
        stats.shutdown();
        statsThread.interrupt();
        throw e;
      }
      catch (InterruptedException e)
      {

      }
      LOG.info("Done with audit- end of stream reached\n");
      return stats.getNumProcessed() == stats.getNumDataEqual();
    }

    public boolean compareRecordsNew() throws SQLException
    {
      AuditStats stats = new AuditStats();
      Thread statsThread = new Thread(stats);
      try
      {
        ResultSet srcRs = null;
        ResultSet destRs = null;

        statsThread.start();

        String lastSrcKey = "0";
        String lastDestKey = "0";
        int compareResult = 0;
        boolean oracleDone = true;
        boolean bootstrapDone = true;
        boolean done = false;
        while (!done)
        {

          // Read the next chunks from src and dest db's
          if (oracleDone)
          {
            done = true;
            DBHelper.close(srcRs);
            srcRs = _srcReader.getRecords(lastSrcKey);
          }

          if (bootstrapDone)
          {
            done = true;
            DBHelper.close(destRs);
            destRs = _destReader.getRecords(lastDestKey);
          }

          // Iterate over two streams in 'key' order
          if (compareResult <= 0)
          {
            oracleDone = !srcRs.next();
          }
          if (compareResult >= 0)
          {
            bootstrapDone = !destRs.next();
          }

          done = done && (bootstrapDone || oracleDone);
          if (!bootstrapDone && !oracleDone)
          {
            // TODO: sampling
            stats.incNumProcessed();
            /* The keys on which the query result set is ordered */
            lastSrcKey = getKey(srcRs);
            lastDestKey = destRs.getString(3);
            compareResult = keyCompare(lastSrcKey, lastDestKey);
            // Compare txn_id, key of both oracle and bs sources;
            // src_txn (oracle) , dst_txn(bootstrap) : destKey is the key field
            // in bs and srcKey is corresponding one in oracle
            if (compareResult == 0)
            {
              stats.incNumKeyEqual();
              /* For reading txnid, key which will form the basis of comparison */
              long srcTxnId = srcRs.getLong(2);
              long dstTxnId = getDestTxnId(destRs);

              // assumption: txnids are monotonically increasing
              if (srcTxnId == dstTxnId)
              {
                boolean result = _auditor
                    .compareRecord(srcRs, destRs, _decoder);
                if (result)
                {
                  stats.incNumDataEqual();
                }
                else
                {
                  LOG.error("Compare error: Key=" + lastSrcKey);
                }
              }
              else if (srcTxnId < dstTxnId)
              {
                // older txn in oracle - this cannot happen
                stats.incNumOlderTxnInOracle();
              }
              else
              {
                // older txn in bootstrap;
                stats.incNumOlderTxnInBootstrap();
              }
            }
            else if (compareResult < 0)
            {
              LOG.info("Absent in bootstrap: " + lastSrcKey);
              // key present in oracle but not in bootstrap;
              stats.incNumKeyAbsentInBootstrap();
            }
            else
            {
              LOG.info("Absent in oracle: " + lastDestKey);
              // key present in bootstrap but not in oracle;
              stats.incNumnKeyAbsentInOracle();
            }
          }
          else if (!bootstrapDone && oracleDone)
          {
            compareResult = -1;
          }
          else if (!oracleDone && bootstrapDone)
          {
            compareResult = 1;
          }
          else
          {
            compareResult = 0;
          }
        }
        LOG.info("Done with audit- end of stream reached\n");
        stats.shutdown();
        statsThread.interrupt();
        statsThread.join();
        return stats.getNumProcessed() == stats.getNumDataEqual();
      }
      catch (SQLException e)
      {
        stats.shutdown();
        statsThread.interrupt();
        throw e;
      }
      catch (InterruptedException e)
      {

      }
      LOG.info("Done with audit- end of stream reached\n");
      return stats.getNumProcessed() == stats.getNumDataEqual();
    }

    protected String getKey(ResultSet srcRs) throws SQLException
    {
      if (_pKeyType == DbusEventKey.KeyType.LONG)
      {
        Long key = srcRs.getLong(_pKey);
        return key.toString();
      }
      return srcRs.getString(_pKey);
    }

    protected int keyCompare(String keySrc, String keyDst)
    {

      if (_pKeyType == DbusEventKey.KeyType.LONG)
      {
        long srcKeyLong = Long.parseLong(keySrc);
        long destKeyLong = Long.parseLong(keyDst);
        if (srcKeyLong == destKeyLong)
        {
          return 0;
        }
        return (srcKeyLong < destKeyLong) ? -1 : 1;
      }
      return keySrc.compareTo(keyDst);
    }

    private long getDestTxnId(ResultSet bsRes) throws SQLException
    {
      GenericRecord avroRec = _auditor.getGenericRecord(bsRes, _decoder);
      if (avroRec == null)
      {
        LOG.error("No avro record skipping");
        return 0;
      }
      Object txnId = avroRec.get("txn");
      if (txnId == null)
      {
        LOG.error("Could not find a field called 'txn' in avro event in bootstrap db");
        return 0;
      }
      switch (_txnType)
      {
      case LONG:
        if (txnId instanceof Integer)
        {
          Integer i = (Integer) txnId;
          return i.longValue();
        }
        else if (txnId instanceof Long)
        {
          return (Long) txnId;
        }
      case INT:
        Integer i = (Integer) txnId;
        return i.longValue();
      default:
        return 0;
      }
    }
  }

  public static class MySQLTableReader extends BootstrapAuditTableReader
  {
    private PreparedStatement _pointRecordStmt = null;
    private PreparedStatement _rangeRecordStmt = null;
    private PreparedStatement _sequentialRangeRecordStmt = null;

    public MySQLTableReader(Connection conn, String tableName, Field pkeyField,
        String pkeyName, Type pkeyType, int interval) throws SQLException
    {
      super(conn, tableName, pkeyField, pkeyName, pkeyType, interval);
      StringBuilder sql = new StringBuilder();
      sql.append("select id,scn,srckey,val from ").append(_tableName);
      sql.append(" where srckey= ?");

      _pointRecordStmt = _conn.prepareStatement(sql.toString());

      StringBuilder sqlSequence = new StringBuilder();
      sqlSequence.append("select id,scn,srckey,val from ").append(_tableName);
      sqlSequence.append(" where id > ? limit ? ");
      _sequentialRangeRecordStmt = _conn.prepareStatement(sqlSequence
          .toString());
    }

    public ResultSet getRecordsSequential(long lastDestId) throws SQLException
    {
      ResultSet rs = null;
      try
      {
        _sequentialRangeRecordStmt.setLong(1, lastDestId);
        _sequentialRangeRecordStmt.setLong(2, _interval);
        rs = _sequentialRangeRecordStmt.executeQuery();
      }
      catch (SQLException sqlEx)
      {
        DBHelper.close(rs, _sequentialRangeRecordStmt, null);
        throw sqlEx;
      }
      return rs;
    }

    @Override
    public void close()
    {
      DBHelper.close(_pointRecordStmt);
      DBHelper.close(_rangeRecordStmt);
      DBHelper.close(_sequentialRangeRecordStmt);
      super.close();
    }

    /**
     *
     * @param lastSrcKey
     *          : a srckey ;
     * @return resultSet that may contain a row whose srckey=lastSrckey;
     * @throws SQLException
     */
    public ResultSet getRecord(String lastSrcKey) throws SQLException
    {
      ResultSet rs = null;
      try
      {
        _pointRecordStmt.setString(1, lastSrcKey);
        // stmt.setFetchSize(10000);
        // stmt.setMaxRows(10);
        rs = _pointRecordStmt.executeQuery();
      }
      catch (SQLException sqlEx)
      {
        DBHelper.close(rs, _pointRecordStmt, null);
        throw sqlEx;
      }
      return rs;
    }


    @Override
    public PreparedStatement getFetchStmt(String from) throws SQLException
    {
      try
      {
        if (_rangeRecordStmt == null || _rangeRecordStmt.isClosed())
        {

          StringBuilder sql = new StringBuilder();
          /**
           * Ordering should be same as the other stream: srckey is a string
           * (type: varchar)
           */
          sql.append(" select id, scn, srckey, val from ").append(_tableName);
          if (_pkeyType == Type.LONG || _pkeyType == Type.INT)
          {
            sql.append(" where cast(srckey as decimal(40)) > ?  order by ");
            sql.append(" cast(srckey as decimal(40)) asc");
          }
          else
          {
            sql.append(" where srckey > ?  order by ");
            sql.append(" srckey asc");
          }
          sql.append(" limit ? ");
          String stmtStr = sql.toString();
          LOG.info("MySQL Query=" + stmtStr);
          _rangeRecordStmt = _conn.prepareStatement(stmtStr);
        }
        LOG.info("MySQL Query params: FromSrcKey= " + from + ",Limit="
            + (_interval));
        _rangeRecordStmt.setString(1, from);
        _rangeRecordStmt.setLong(2, _interval);
        return _rangeRecordStmt;
      }
      catch (SQLException e)
      {
        DBHelper.close(null, _rangeRecordStmt, null);
        _rangeRecordStmt = null;
        throw e;
      }
    }

  }

  public static class OracleTableReader extends BootstrapAuditTableReader
  {
    private final DbusEventKey.KeyType _dbusKeyType;
    private final String _pkIndex;
    private final String _queryHint;
    private PreparedStatement _pointRecordStmt = null;
    private PreparedStatement _rangeRecordStmt = null;

    Method _setLobPrefetchSizeMethod = null;
    Class<?> _oraclePreparedStatementClass = null;

    public OracleTableReader(Connection conn, String tableName,
        Field pkeyField, String pkeyName, Type pkeyType, int interval,
        String pkIndex, String queryHint) throws SQLException
    {
      super(conn, tableName, pkeyField, pkeyName, pkeyType, interval);

      if ((pkeyType == Type.INT) || (pkeyType == Type.LONG))
      {
        _dbusKeyType = DbusEventKey.KeyType.LONG;
      }
      else
      {
        _dbusKeyType = DbusEventKey.KeyType.STRING;
      }

      _pkIndex = pkIndex;
      _queryHint = queryHint;

      String pointRecordsql = generatePointQuery(_tableName, _pkeyName,
          _pkIndex, _queryHint);
      _pointRecordStmt = _conn.prepareStatement(pointRecordsql);

      LOG.info("Tablename=" + tableName);
      LOG.info("Point Oracle Query =" + pointRecordsql);

      try
      {
        _oraclePreparedStatementClass = OracleJarUtils
            .loadClass("oracle.jdbc.OraclePreparedStatement");
        _setLobPrefetchSizeMethod = _oraclePreparedStatementClass.getMethod(
            "setLobPrefetchSize", int.class);
      }
      catch (Exception e)
      {
        LOG.error("Exception raised while trying to get oracle methods", e);
        throw new SQLException(e.getMessage());
      }
    }

    public String generatePointQuery(String table, String keyName,
        String pkIndex, String queryHint)
    {
      StringBuilder sql = new StringBuilder();

      if ((null == queryHint) || (queryHint.isEmpty()))
        sql.append("select /*+ INDEX(src ").append(pkIndex).append(") */ ");
      else
        sql.append("select /*+ " + queryHint + " */ ");

      sql.append(keyName).append(" keyn,");
      sql.append(" txn txnid, src.* ").append(" from ");
      sql.append(table);
      sql.append(" src");
      sql.append(" where src." + keyName + " = ?");
      return sql.toString();
    }

    @Override
    public void close()
    {
      DBHelper.close(_pointRecordStmt);
      DBHelper.close(_rangeRecordStmt);
      super.close();
    }

    /**
     *
     * @param destKey
     *          : the srckey
     * @return ResultSet
     * @throws SQLException
     */
    public ResultSet getRecord(String destKey) throws SQLException
    {
      ResultSet rs = null;
      try
      {
        // Reuse prepared statement
        _pointRecordStmt.setString(1, destKey);
        // stmt.setFetchSize(10000);
        // stmt.setMaxRows(10);
        rs = _pointRecordStmt.executeQuery();
      }
      catch (SQLException sqlEx)
      {
        DBHelper.close(rs, _pointRecordStmt, null);
        throw sqlEx;
      }
      return rs;
    }

    @Override
    public PreparedStatement getFetchStmt(String from) throws SQLException

    {
      try
      {
        if (_rangeRecordStmt == null || _rangeRecordStmt.isClosed())
        {

          String sql = BootstrapSrcDBEventReader.generateEventQueryAudit(
              _tableName, _pkeyName, _dbusKeyType, _pkIndex, _queryHint);
          LOG.info("Oracle Query =" + sql);

          _rangeRecordStmt = _conn.prepareStatement(sql);
          Object ds = _oraclePreparedStatementClass.cast(_rangeRecordStmt);
          try
          {
            _setLobPrefetchSizeMethod.invoke(ds, 1000);
          }
          catch (Exception e)
          {
            LOG.error("Could not set LobPreFetchSize: " + e);
            throw new SQLException(e.getMessage());
          }
        }
        LOG.info("Oracle Query: From=" + from + " interval=" + _interval);
        _rangeRecordStmt.setString(1, from);
        _rangeRecordStmt.setLong(2, _interval);
        return _rangeRecordStmt;
      }
      catch (SQLException e)
      {
        DBHelper.close(_rangeRecordStmt);
        throw e;
      }
    }
  }

  public static class KeyTxnReader
  {
    private final BufferedReader _reader;

    public KeyTxnReader(File file)
    {
      try
      {
        _reader = new BufferedReader(StringUtils.createFileReader(file));
      }
      catch (IOException ioe)
      {
        LOG.error("KeyTxnReader error: " + ioe.getMessage(), ioe);
        throw new RuntimeException(ioe);
      }
    }

    public boolean readNextEntry(PrimaryKeyTxn entry) throws IOException
    {
      String line = _reader.readLine();

      if (null == line)
        return false;

      entry.readFrom(line);
      return true;
    }

    public void close()
    {
      try
      {
        _reader.close();
      }
      catch (IOException ioe)
      {
        LOG.error("KeyTxnReader error: " + ioe.getMessage(), ioe);
      }
    }
  }

}
TOP

Related Classes of com.linkedin.databus.bootstrap.utils.BootstrapAuditMain

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.