Search in sources :

Example 1 with BootstrapCheckpointHandler

use of com.linkedin.databus.core.BootstrapCheckpointHandler in project databus by linkedin.

the class TestNettyHttpDatabusBootstrapConnection method testServerBootstrapDisconnect.

@Test
public /**
 * This is a unit test for DDSDBUS-3537. There is a lag between a network channel disconnect and the
 * state change in AbstractNettyHttpConnection. This can cause a race condition in various requestXXX objects which
 * check the state of the connection using the network channel. As a result, they may attempt to reconnect while
 * AbstractNettyHttpConnection is still in CONNECTED state which causes an error for an incorrect transition
 * CONNECTED -> CONNECTING.
 *
 *  The test simulates the above condition by injecting a handler in the client pipeline which artificially holds up
 *  the channelClosed message. As a result we can inject a request while the netty channel is disconnected but the
 *  AbstractNettyHttpConnection object has not detected this yet.
 */
void testServerBootstrapDisconnect() throws Exception {
    final Logger log = Logger.getLogger("TestNettyHttpDatabusBootstrapConnection.testServerBootstrapDisconnect");
    log.info("starting");
    log.info("setup the client");
    TestingConnectionCallback callback = TestingConnectionCallback.createAndStart("testServerSourcesDisconnect");
    DummyRemoteExceptionHandler remoteExceptionHandler = new DummyRemoteExceptionHandler();
    final NettyHttpDatabusBootstrapConnection conn = (NettyHttpDatabusBootstrapConnection) CONN_FACTORY.createConnection(BOOTSTRAP_SERVER_INFO, callback, remoteExceptionHandler);
    try {
        log.info("initial setup");
        final List<String> sourceNamesList = Arrays.asList(SOURCE1_NAME);
        final Checkpoint cp = Checkpoint.createOnlineConsumptionCheckpoint(0);
        BootstrapCheckpointHandler cpHandler = new BootstrapCheckpointHandler(sourceNamesList);
        cpHandler.createInitialBootstrapCheckpoint(cp, 0L);
        final DummyDatabusBootstrapConnectionStateMessage bstCallback = new DummyDatabusBootstrapConnectionStateMessage(log);
        log.info("process a normal startSCN which should establish the connection");
        sendStartScnHappyPath(conn, cp, bstCallback, SOURCE1_NAME, 100L, log);
        Assert.assertTrue(conn.isConnected());
        // wait for the response
        TestUtil.assertWithBackoff(new ConditionCheck() {

            @Override
            public boolean check() {
                return null != bstCallback.getCheckpoint();
            }
        }, "wait for /startSCN response", 100, log);
        log.info("verify /startSCN response");
        final Checkpoint startScnCp = bstCallback.getCheckpoint();
        Assert.assertNotNull(startScnCp);
        Assert.assertEquals(100L, startScnCp.getBootstrapStartScn().longValue());
        log.info("instrument the client pipeline so that we can intercept and delay the channelClosed message");
        final Semaphore passMessage = new Semaphore(1);
        final CountDownLatch closeSent = new CountDownLatch(1);
        passMessage.acquire();
        conn._channel.getPipeline().addBefore("handler", "closeChannelDelay", new SimpleChannelHandler() {

            @Override
            public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
                closeSent.countDown();
                passMessage.acquire();
                try {
                    super.channelClosed(ctx, e);
                } finally {
                    passMessage.release();
                }
            }
        });
        final Channel serverChannel = getServerChannelForClientConn(conn);
        Thread asyncChannelClose = new Thread(new Runnable() {

            @Override
            public void run() {
                log.info("closing server channel");
                serverChannel.close();
                log.info("server channel: closed");
                closeSent.countDown();
            }
        }, "asyncChannelCloseThread");
        asyncChannelClose.setDaemon(true);
        Thread asyncBootstrapReq = new Thread(new Runnable() {

            @Override
            public void run() {
                conn.requestStream("1", null, 10000, startScnCp, bstCallback);
            }
        }, "asyncBootstrapReqThread");
        asyncBootstrapReq.setDaemon(true);
        log.info("simultaneously closing connection and sending /bootstrap request");
        bstCallback.reset();
        asyncChannelClose.start();
        Assert.assertTrue(closeSent.await(1000, TimeUnit.MILLISECONDS));
        TestUtil.assertWithBackoff(new ConditionCheck() {

            @Override
            public boolean check() {
                return !conn._channel.isConnected();
            }
        }, "waiting for disconnect on the client side", 1000, log);
        Assert.assertEquals(AbstractNettyHttpConnection.State.CONNECTED, conn.getNetworkState());
        log.info("asynchronously sending /bootstrap");
        asyncBootstrapReq.start();
        log.info("letting channelClose get through");
        TestUtil.assertWithBackoff(new ConditionCheck() {

            @Override
            public boolean check() {
                return bstCallback.isStreamRequestError();
            }
        }, "wait for streamRequestError callback", 1000, log);
        passMessage.release();
        log.info("finished");
    } finally {
        conn.close();
        callback.shutdown();
        log.info("cleaned");
    }
}
Also used : ConditionCheck(com.linkedin.databus2.test.ConditionCheck) ChunkedBodyReadableByteChannel(com.linkedin.databus.client.ChunkedBodyReadableByteChannel) Channel(org.jboss.netty.channel.Channel) ChannelHandlerContext(org.jboss.netty.channel.ChannelHandlerContext) Semaphore(java.util.concurrent.Semaphore) Logger(org.apache.log4j.Logger) CountDownLatch(java.util.concurrent.CountDownLatch) BootstrapCheckpointHandler(com.linkedin.databus.core.BootstrapCheckpointHandler) InvalidConfigException(com.linkedin.databus.core.util.InvalidConfigException) JsonGenerationException(org.codehaus.jackson.JsonGenerationException) JsonMappingException(org.codehaus.jackson.map.JsonMappingException) IOException(java.io.IOException) Checkpoint(com.linkedin.databus.core.Checkpoint) ChannelStateEvent(org.jboss.netty.channel.ChannelStateEvent) SimpleChannelHandler(org.jboss.netty.channel.SimpleChannelHandler) Test(org.testng.annotations.Test)

Example 2 with BootstrapCheckpointHandler

use of com.linkedin.databus.core.BootstrapCheckpointHandler in project databus by linkedin.

the class CheckpointSerializerMain method updateCheckpoint.

private static Checkpoint updateCheckpoint(Checkpoint cpOld) throws JsonParseException, JsonMappingException, IOException {
    Checkpoint cpNew = null != cpOld ? new Checkpoint(cpOld.toString()) : new Checkpoint();
    if (null != _scn) {
        if (-1L != _scn) {
            cpNew.setWindowScn(_scn);
            cpNew.setWindowOffset(0);
        } else {
            cpNew.setFlexible();
        }
    }
    if (null != _startScn) {
        cpNew.setBootstrapStartScn(_startScn);
    }
    if (null != _targetScn) {
        cpNew.setBootstrapTargetScn(_targetScn);
    }
    if (null != _cpType) {
        cpNew.setConsumptionMode(_cpType);
        switch(_cpType) {
            case ONLINE_CONSUMPTION:
                cpNew.setWindowOffset(0);
                break;
            /*
         * TODO Disabling as the bootstrap checkpoint creation leaves out important
         * information (e.g. catchup/snashot source index) out of the checkpoint
         * and thus is incorrect. We have to figure out what types of bootstrap
         * checkpoints it makes sense to create.
        case BOOTSTRAP_CATCHUP:
        {
          if (null != _bootstrapSource) cpNew.setCatchupSource(_bootstrapSource);
          cpNew.setCatchupOffset(-1);
          break;
        }*/
            case BOOTSTRAP_SNAPSHOT:
                {
                    BootstrapCheckpointHandler handler = new BootstrapCheckpointHandler(_sources);
                    cpNew = handler.createInitialBootstrapCheckpoint(cpNew, _sinceScn);
                    // if (null != _bootstrapSource) cpNew.setSnapshotSource(_bootstrapSource);
                    cpNew.setSnapshotOffset(-1);
                    break;
                }
            default:
                throw new DatabusRuntimeException("unsupported checkpoint type: " + _cpType);
        }
    }
    return cpNew;
}
Also used : Checkpoint(com.linkedin.databus.core.Checkpoint) BootstrapCheckpointHandler(com.linkedin.databus.core.BootstrapCheckpointHandler) DatabusRuntimeException(com.linkedin.databus.core.DatabusRuntimeException)

Example 3 with BootstrapCheckpointHandler

use of com.linkedin.databus.core.BootstrapCheckpointHandler in project databus by linkedin.

the class BootstrapPullThread method determineNextStateFromCheckpoint.

/**
 * Determines the next state based on the checkpoint. The idea is to determine where we are in the bootstrap flow and
 * move to the next state.
 *
 *  <pre>
 *    1. Request startSCN (State=REQUEST_START_SCN, SNAPSHOT, !cp.isBootstrapStartScnSet())
 *    2. For each snapshot source:
 *       2.1. Start snapshot (State=REQUEST_STREAM, SNAPSHOT, cp.isBootstrapStartScnSet() &&
 *                            0 == cp.getSnapshotOffset())
 *       2.2. While (! cp.isSnapShotSourceCompleted())
 *          2.2.1. Continue snapshot (State=REQUEST_STREAM, SNAPSHOT, cp.isBootstrapStartScnSet() &&
 *                                    0 < cp.getSnapshotOffset())
 *       2.3. Request targetSCN (State=REQUEST_TARGET_SCN, SNAPSHOT, cp.isBootstrapStartScnSet() &&
 *                               cp.isSnapShotSourceCompleted() && 0 == cp.getWindowOffset())
 *       2.4. For each catchup source <= the snapshot source:
 *          2.4.1. Start catchup (State=REQUEST_STREAM, CATCHUP, 0==cp.getWindowOffset() && handler.needsMoreCatchup())
 *          2.4.2. While (! cp.isCatchupSourceCompleted())
 *             2.4.2.1. Continue catchup (State=REQUEST_STREAM, CATCHUP, ! cp.isCatchupSourceCompleted())
 *  </pre>
 * @param curState        the bootstrap checkpoint
 */
private void determineNextStateFromCheckpoint(ConnectionState curState) {
    try {
        final Checkpoint cp = curState.getCheckpoint();
        final BootstrapCheckpointHandler cpHandler = curState.getBstCheckpointHandler();
        cpHandler.assertBootstrapCheckpoint(cp);
        switch(cp.getConsumptionMode()) {
            case BOOTSTRAP_SNAPSHOT:
                determineNextStateFromSnapshotCheckpoint(cp, cpHandler, curState);
                break;
            case BOOTSTRAP_CATCHUP:
                determineNextStateFromCatchupCheckpoint(cp, cpHandler, curState);
                break;
            default:
                _log.fatal("unexpected bootstrap checkpoint type: " + cp + "; shutting down");
                curState.switchToClosed();
        }
    } catch (InvalidCheckpointException e) {
        _log.fatal("invalid bootstrap checkpoint:", e);
        curState.switchToClosed();
    }
}
Also used : Checkpoint(com.linkedin.databus.core.Checkpoint) InvalidCheckpointException(com.linkedin.databus.core.InvalidCheckpointException) BootstrapCheckpointHandler(com.linkedin.databus.core.BootstrapCheckpointHandler)

Example 4 with BootstrapCheckpointHandler

use of com.linkedin.databus.core.BootstrapCheckpointHandler in project databus by linkedin.

the class BootstrapPullThread method doReadBootstrapEvents.

protected void doReadBootstrapEvents(ConnectionState curState) {
    boolean success = true;
    boolean debugEnabled = _log.isDebugEnabled();
    boolean enqueueMessage = true;
    try {
        Checkpoint cp = curState.getCheckpoint();
        DbusEventBuffer eventBuffer = curState.getDataEventsBuffer();
        if (debugEnabled)
            _log.debug("Sending bootstrap events to buffer");
        // eventBuffer.startEvents();
        DbusEventInternalReadable cpEvent = getEventFactory().createCheckpointEvent(cp);
        byte[] cpEventBytes = new byte[cpEvent.size()];
        if (debugEnabled) {
            _log.debug("checkpoint event size: " + cpEventBytes.length);
            _log.debug("checkpoint event:" + cpEvent.toString());
        }
        cpEvent.getRawBytes().get(cpEventBytes);
        ByteArrayInputStream cpIs = new ByteArrayInputStream(cpEventBytes);
        ReadableByteChannel cpRbc = Channels.newChannel(cpIs);
        UnifiedClientStats unifiedClientStats = _sourcesConn.getUnifiedClientStats();
        sendHeartbeat(unifiedClientStats);
        int ecnt = eventBuffer.readEvents(cpRbc);
        success = (ecnt > 0);
        if (!success) {
            _log.error("Unable to write bootstrap phase marker");
        } else {
            ChunkedBodyReadableByteChannel readChannel = curState.getReadChannel();
            String remoteErrorName = RemoteExceptionHandler.getExceptionName(readChannel);
            Throwable remoteError = _remoteExceptionHandler.getException(readChannel);
            if (null != remoteError && remoteError instanceof BootstrapDatabaseTooOldException) {
                _log.error("Bootstrap database is too old!");
                _remoteExceptionHandler.handleException(remoteError);
                curState.switchToStreamResponseError();
            } else if (null != remoteErrorName) {
                // remote processing error
                _log.error("read events error: " + RemoteExceptionHandler.getExceptionMessage(readChannel));
                curState.switchToStreamResponseError();
            } else {
                sendHeartbeat(unifiedClientStats);
                int eventsNum = eventBuffer.readEvents(readChannel, curState.getListeners(), _sourcesConn.getBootstrapEventsStatsCollector());
                if (eventsNum == 0 && _remoteExceptionHandler.getPendingEventSize(readChannel) > eventBuffer.getMaxReadBufferCapacity()) {
                    String err = "ReadBuffer max capacity(" + eventBuffer.getMaxReadBufferCapacity() + ") is less than event size(" + _remoteExceptionHandler.getPendingEventSize(readChannel) + "). Increase databus.client.connectionDefaults.bstEventBuffer.maxEventSize and restart.";
                    _log.fatal(err);
                    enqueueMessage(LifecycleMessage.createSuspendOnErroMessage(new PendingEventTooLargeException(err)));
                    return;
                } else {
                    resetServerRetries();
                    if (debugEnabled)
                        _log.debug("Sending events to buffer");
                    numEventsInCurrentState += eventsNum;
                    _log.info("Bootstrap events read so far: " + numEventsInCurrentState);
                    String status = readChannel.getMetadata("PhaseCompleted");
                    final BootstrapCheckpointHandler ckptHandler = curState.getBstCheckpointHandler();
                    if (status != null) {
                        // set status in checkpoint to indicate that we are done with the current source
                        if (cp.getConsumptionMode() == DbusClientMode.BOOTSTRAP_CATCHUP) {
                            ckptHandler.finalizeCatchupPhase(cp);
                        } else if (cp.getConsumptionMode() == DbusClientMode.BOOTSTRAP_SNAPSHOT) {
                            ckptHandler.finalizeSnapshotPhase(cp);
                        } else {
                            throw new RuntimeException("Invalid bootstrap phase: " + cp.getConsumptionMode());
                        }
                        _log.info("Bootstrap events read :" + numEventsInCurrentState + " during phase:" + cp.getConsumptionMode() + " [" + cp.getBootstrapSnapshotSourceIndex() + "," + cp.getBootstrapCatchupSourceIndex() + "]");
                        numEventsInCurrentState = 0;
                    } else {
                        // question: how is snapshotOffset maintained in ckpt
                        if (eventsNum > 0) {
                            cp.bootstrapCheckPoint();
                        }
                    }
                    curState.switchToStreamResponseDone();
                }
            }
        }
    } catch (InterruptedException ie) {
        _log.error("interupted", ie);
        success = false;
    } catch (InvalidEventException e) {
        _log.error("error reading events from server: " + e.getMessage(), e);
        success = false;
    } catch (RuntimeException e) {
        _log.error("runtime error reading events from server: " + e.getMessage(), e);
        success = false;
    }
    if (toTearConnAfterHandlingResponse()) {
        tearConnectionAndEnqueuePickServer();
        enqueueMessage = false;
    } else if (!success) {
        curState.switchToPickServer();
    }
    if (enqueueMessage)
        enqueueMessage(curState);
}
Also used : ReadableByteChannel(java.nio.channels.ReadableByteChannel) UnifiedClientStats(com.linkedin.databus.client.pub.mbean.UnifiedClientStats) PendingEventTooLargeException(com.linkedin.databus.core.PendingEventTooLargeException) DbusEventInternalReadable(com.linkedin.databus.core.DbusEventInternalReadable) Checkpoint(com.linkedin.databus.core.Checkpoint) BootstrapCheckpointHandler(com.linkedin.databus.core.BootstrapCheckpointHandler) DbusEventBuffer(com.linkedin.databus.core.DbusEventBuffer) BootstrapDatabaseTooOldException(com.linkedin.databus2.core.container.request.BootstrapDatabaseTooOldException) Checkpoint(com.linkedin.databus.core.Checkpoint) ByteArrayInputStream(java.io.ByteArrayInputStream) InvalidEventException(com.linkedin.databus.core.InvalidEventException)

Example 5 with BootstrapCheckpointHandler

use of com.linkedin.databus.core.BootstrapCheckpointHandler in project databus by linkedin.

the class TestBootstrap method testBootstrapProcessor.

@Test
public void testBootstrapProcessor() throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException, IOException, BootstrapProcessingException, DatabusException, BootstrapDatabaseTooOldException, BootstrapDBException {
    EventProcessor processorCallback = new EventProcessor();
    BootstrapConfig config = new BootstrapConfig();
    BootstrapReadOnlyConfig staticConfig = config.build();
    BootstrapServerConfig configBuilder = new BootstrapServerConfig();
    configBuilder.setEnableMinScnCheck(false);
    BootstrapServerStaticConfig staticServerConfig = configBuilder.build();
    BootstrapProcessor processor = new BootstrapProcessor(staticServerConfig, null);
    String sourceName = "TestBootstrap.testBootstrapProcessor.events";
    // Create the tables for all the sources before starting up the threads
    BootstrapConn _bootstrapConn = new BootstrapConn();
    boolean autoCommit = true;
    _bootstrapConn.initBootstrapConn(autoCommit, staticConfig.getBootstrapDBUsername(), staticConfig.getBootstrapDBPassword(), staticConfig.getBootstrapDBHostname(), staticConfig.getBootstrapDBName());
    BootstrapDBMetaDataDAO dao = new BootstrapDBMetaDataDAO(_bootstrapConn, staticConfig.getBootstrapDBHostname(), staticConfig.getBootstrapDBUsername(), staticConfig.getBootstrapDBPassword(), staticConfig.getBootstrapDBName(), autoCommit);
    SourceStatusInfo srcStatusInfo = dao.getSrcIdStatusFromDB(sourceName, false);
    if (srcStatusInfo.getSrcId() >= 0) {
        dao.dropSourceInDB(srcStatusInfo.getSrcId());
    }
    dao.addNewSourceInDB(sourceName, BootstrapProducerStatus.ACTIVE);
    srcStatusInfo = dao.getSrcIdStatusFromDB(sourceName, false);
    setBootstrapLoginfoTable(_bootstrapConn, 0, Long.MAX_VALUE);
    // insert one row
    insertOneSnapshotEvent(dao, srcStatusInfo.getSrcId(), Long.MAX_VALUE - 10, Long.MAX_VALUE - 100, "check", "test_payload_data");
    BootstrapCheckpointHandler bstCheckpointHandler = new BootstrapCheckpointHandler(sourceName);
    Checkpoint c = bstCheckpointHandler.createInitialBootstrapCheckpoint(null, 0L);
    c.setConsumptionMode(DbusClientMode.BOOTSTRAP_SNAPSHOT);
    c.setBootstrapStartScn(Long.MAX_VALUE - 10);
    c.setSnapshotOffset(Long.MAX_VALUE - 1000);
    // System.out.println("Snapshot");
    processor.streamSnapShotRows(c, processorCallback);
    Assert.assertEquals(processorCallback.getrIds().size(), 1);
    Assert.assertEquals(Long.MAX_VALUE - 10, processorCallback.getrIds().get(0).longValue());
    Assert.assertEquals(Long.MAX_VALUE - 100, processorCallback.getSequences().get(0).longValue());
    Assert.assertEquals("check", processorCallback.getSrcKeys().get(0));
    Assert.assertEquals("test_payload_data", new String(processorCallback.getValues().get(0)));
    processorCallback.reset();
    c.setSnapshotOffset(Checkpoint.FULLY_CONSUMED_WINDOW_OFFSET);
    c.setBootstrapTargetScn(c.getBootstrapStartScn().longValue());
    bstCheckpointHandler.advanceAfterTargetScn(c);
    bstCheckpointHandler.advanceAfterSnapshotPhase(c);
    // c.setConsumptionMode(DbusClientMode.BOOTSTRAP_CATCHUP);
    // c.setCatchupSource(sourceName);
    // c.setWindowScn(0L);
    // c.setWindowOffset(0);
    // System.out.println("Catchup");
    boolean phaseCompleted = processor.streamCatchupRows(c, processorCallback);
    Assert.assertEquals(true, phaseCompleted);
}
Also used : BootstrapProcessor(com.linkedin.databus.bootstrap.server.BootstrapProcessor) BootstrapConn(com.linkedin.databus.bootstrap.common.BootstrapConn) BootstrapConfig(com.linkedin.databus.bootstrap.common.BootstrapConfig) BootstrapDBMetaDataDAO(com.linkedin.databus.bootstrap.common.BootstrapDBMetaDataDAO) BootstrapCheckpointHandler(com.linkedin.databus.core.BootstrapCheckpointHandler) BootstrapReadOnlyConfig(com.linkedin.databus.bootstrap.common.BootstrapReadOnlyConfig) BootstrapServerConfig(com.linkedin.databus.bootstrap.server.BootstrapServerConfig) Checkpoint(com.linkedin.databus.core.Checkpoint) BootstrapServerStaticConfig(com.linkedin.databus.bootstrap.server.BootstrapServerStaticConfig) SourceStatusInfo(com.linkedin.databus.bootstrap.common.BootstrapDBMetaDataDAO.SourceStatusInfo) Test(org.testng.annotations.Test)

Aggregations

BootstrapCheckpointHandler (com.linkedin.databus.core.BootstrapCheckpointHandler)6 Checkpoint (com.linkedin.databus.core.Checkpoint)6 Test (org.testng.annotations.Test)3 Logger (org.apache.log4j.Logger)2 BootstrapConfig (com.linkedin.databus.bootstrap.common.BootstrapConfig)1 BootstrapConn (com.linkedin.databus.bootstrap.common.BootstrapConn)1 BootstrapDBMetaDataDAO (com.linkedin.databus.bootstrap.common.BootstrapDBMetaDataDAO)1 SourceStatusInfo (com.linkedin.databus.bootstrap.common.BootstrapDBMetaDataDAO.SourceStatusInfo)1 BootstrapReadOnlyConfig (com.linkedin.databus.bootstrap.common.BootstrapReadOnlyConfig)1 BootstrapProcessor (com.linkedin.databus.bootstrap.server.BootstrapProcessor)1 BootstrapServerConfig (com.linkedin.databus.bootstrap.server.BootstrapServerConfig)1 BootstrapServerStaticConfig (com.linkedin.databus.bootstrap.server.BootstrapServerStaticConfig)1 ChunkedBodyReadableByteChannel (com.linkedin.databus.client.ChunkedBodyReadableByteChannel)1 DatabusV2ConsumerRegistration (com.linkedin.databus.client.consumer.DatabusV2ConsumerRegistration)1 MultiConsumerCallback (com.linkedin.databus.client.consumer.MultiConsumerCallback)1 StreamConsumerCallbackFactory (com.linkedin.databus.client.consumer.StreamConsumerCallbackFactory)1 UnifiedClientStats (com.linkedin.databus.client.pub.mbean.UnifiedClientStats)1 DatabusRuntimeException (com.linkedin.databus.core.DatabusRuntimeException)1 DbusEvent (com.linkedin.databus.core.DbusEvent)1 DbusEventBuffer (com.linkedin.databus.core.DbusEventBuffer)1