package com.linkedin.databus.client.pub; /* * * 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.List; import org.apache.log4j.Logger; import com.linkedin.databus.client.pub.mbean.ConsumerCallbackStatsMBean; import com.linkedin.databus.client.pub.mbean.UnifiedClientStatsMBean; import com.linkedin.databus.core.Checkpoint; import com.linkedin.databus.core.CheckpointMult; import com.linkedin.databus.core.DatabusComponentStatus; import com.linkedin.databus.core.data_model.DatabusSubscription; import com.linkedin.databus.core.data_model.PhysicalPartition; import com.linkedin.databus.core.monitoring.mbean.DbusEventsStatisticsCollectorMBean; import com.linkedin.databus2.core.filter.DbusKeyCompositeFilterConfig; /** * A "registration" represents an identifier for a set of consumer(s) interested in * subscription(s). When we say a "registration" here, we mean "an object of type DatabusV3Registration" * * The user of the client library can specify a "RegistrationId" for the registration. * If that RegistrationId is currently not in use, it is allotted for the returned DatabusV3Registration object. * * If the user does not specify the RegistrationId, the library currently assigns one. The registration gets the * same id upon a restart. * * The persisted checkpoint for this particular consumerGroup is identified * through the RegistrationId, which is a hash generated off the consumer subscriptions. * * {@link DatabusV3Client#registerDatabusListener(DatabusV3Consumer, RegistrationId, DbusKeyCompositeFilterConfig, DatabusSubscription)}/ * {@link DatabusV3Client#registerCluster(String, DbusClusterConsumerFactory, String)} * DatabusClient interface methods implemented by DatabusHttpV3ClientImpl */ public interface DatabusV3Registration { /** * Initiates traffic consumption. After a consumer is registered, and until this call is invoked no * events will be seen. * * A connection is made to an appropriate relay / bootstrap server depending on the subscription and delivered * to the consumer * * @throws IllegalStateException If the registration is started multiple times * * Please note that this method does not declare explicitly that it throws an IllegalStateException. Reasons are explained below: * (1) It was not listed explicitly in releases prior to 2.13.2 * (2) IllegalStateException is a runtime exception, and hence is not required to be declared * (3) We would like to maintain the same API erasure, to ensure no problems for client applications during upgrade. * (4) It may be explicitly declared going forward. */ public StartResult start(); /** * Stops traffic consumption. After completion of this call, all threads pulling events and * invoking this callback will be stopped. It is guaranteed that callbacks will not be invoked anymore. * * The registration object can still be inspected by client REST API. * * @throws IllegalStateException If the registration is not running. */ public void shutdown() throws IllegalStateException; /** * Pauses traffic consumption asynchronously (i.e., an asynchronous call is made to the component which pulls * the events) If there are outstanding events in the client buffer, they will be dispatched to the consumer * until the buffer becomes empty. * * The registration can be paused for an arbitrary length of time, and may be shut down after being paused * (if desired). * * @throws IllegalStateException If the registration is not running */ public void pause() throws IllegalStateException; /** * Suspend traffic consumption. This is similar to the behavior of {{@link #pause()} and is asynchronous in * nature. Client applications are expected to use this API when an error/exception condition causes the client * application to suspend the consumption of events. * * The registration can be suspended for an arbitrary length of time, and may be shut down after being suspended * (if desired). * * @param ex Throwable for the exceptional/error condition. * @throws IllegalStateException If the registration is not running. */ public void suspendOnError(Throwable ex) throws IllegalStateException; /** * Resume traffic consumption. This is an asynchronous call to the component which pulls events from the relay. * This can be called when the consumption is paused/suspended. * * @throws IllegalStateException If the registration is not paused or suspended. */ public void resume() throws IllegalStateException; /** * Returns the internal registration state of the object * * An object of DatabusV3Registration obeys a state-machine with states in {@link RegistrationState} */ public RegistrationState getState(); /** * Stop the data processing of the consumer(s) on the registration. First, it shuts down the connections * between the puller thread in the client to the relay/bootstrap server. Then it, shuts down the event processing * loop on the consumer. * * This is a synchronous operation, and once the deregister is received, events are no longer received. * * TODO : DDSDBUS-2699 * @note WARNING : Prior to 2.13.2, a shutdown would be invoked on the If this is the only registration for which the pull threads, * then a shutdown is invoked on the underlying serverContainer. That behavior is changed now, the application has to explicitly * invoke a shutdown() on the parent registration if a shutdown is required * * @return DeregisterResult * @throws IllegalStateException If the registration is already in DEREGISTERED state * * Please note that this method does not declare explicitly that it throws an IllegalStateException. Reasons are explained below: * (1) It was not listed explicitly in releases prior to 2.13.2 * (2) IllegalStateException is a runtime exception, and hence is not required to be declared * (3) We would like to maintain the same API erasure, to ensure no problems for client applications during upgrade. * (4) It may be explicitly declared going forward. */ public DeregisterResult deregister(); /** * Obtains a cloned Collection of all subscriptions associated with this registration. * Changing this subscription will not have any effect on the registration. */ public List<DatabusSubscription> getSubscriptions(); /** * Returns an object that implements DatabusComponentStatus. * Helpful for obtaining diagnostics regarding the registration, and for invoking diagnostic operations * via JMX like pausing a consumer. */ public DatabusComponentStatus getStatus(); /** * Not exposing an API to expose getFilterConfig as Espresso is inherently partitioned * public DbusKeyCompositeFilterConfig getFilterConfig(); */ /** * Obtains a logger used by databus for logging messages associated with this registration */ public Logger getLogger(); /** * @note WARNING: For Databus internal use only * @deprecated */ @Deprecated public DatabusV3Registration getParentRegistration(); /** * API for building Registration with client-application defined regId. The * ComponentStatus object will be recreated when regId changes. Hence it is * the responsibility for the client application to use the new ComponentStatus * {@link #getStatus()} after calling this API. * * @param regId New Registration Id to be set. * @return this instance after adding regId * @throws DatabusClientException if the regId is already being used. * @throws IllegalStateException if the registration has already started. */ public DatabusV3Registration withRegId(RegistrationId regId) throws DatabusClientException, IllegalStateException; /** * Unlike DatabusRegistration interface, not exposing an API to build a registration * with server-side filter as Espresso is inherently partitioned * * public DatabusV3Registration withServerSideFilter(DbusKeyCompositeFilterConfig filterConfig) * throws IllegalStateException; */ /** * Returns the partition that this registration serves. * * @return Collection<PhysicalPartition> A collection of PhysicalPartition objects */ public Collection<PhysicalPartition> getPhysicalPartitions(); /** * Returns the last persisted checkpoint. It is a copy of the actual checkpoint, so * changing this will not alter the actual checkpoint used by Databus Client. * * @param physicalPartition The partition for which the checkpoint has to be fetched. If only one partition is * associated with this registration, a null or the actual PhysicalPartition should be passed. * @throws DatabusClientException if it violates the following * For client load balanced scenario: The physicalPartition must be one of the partitions hosted in this client instance. * For any other scenario: The physicalPartition must be one of the partitions that the client has subscribed to. */ public Checkpoint getLastPersistedCheckpoint(PhysicalPartition physicalPartition) throws DatabusClientException; /** * Allow the client application to set a checkpoint for a particular physical partition. * * @param ckpt The checkpoint to be set * @param physicalPartition The particular partition for which the checkpoint is set. * @throws IllegalStateException If the registration is not in REGISTERED state. * @throws DatabusClientException if it violates the following * For client load balanced scenario: The physicalPartition must be one of the partitions hosted in this client instance. * For any other scenario: The physicalPartition must be one of the partitions that the client has subscribed to. */ public boolean storeCheckpoint(PhysicalPartition physicalPartition, Checkpoint ckpt) throws DatabusClientException, IllegalStateException; //TODO deprecate this and use storeCheckPoint and getCheckPoint with Partition information instead public CheckpointPersistenceProvider getCheckpointPersistenceProvider(); /** * This method will be deprecated in a future release. * @deprecated Please use {@link #getCheckpointPersistenceProvider() instead} */ @Deprecated public CheckpointPersistenceProvider getCheckpoint(); /** * Obtains the inbound relay event statistics for the registration */ public DbusEventsStatisticsCollectorMBean getRelayEventStats(); /** * Obtains the inbound bootstrap event statistics */ public DbusEventsStatisticsCollectorMBean getBootstrapEventStats(); /** * Obtain statistics for the callbacks for relay events */ public ConsumerCallbackStatsMBean getRelayCallbackStats(); /** * Obtain statistics for the callbacks for bootstrap events */ public ConsumerCallbackStatsMBean getBootstrapCallbackStats(); /** * Returns unified relay/bootstrap statistics for client callbacks */ public UnifiedClientStatsMBean getUnifiedClientStats(); /** * @note WARNING: For Databus internal use only * Applicable for Espresso internal replication only. * * Fetch the most recent sequence number across all relays. * * @param FetchMaxSCNRequest : Request params for fetchMaxSCN * @return RelayFindMaxSCNResult : Contains the result of the fetch call and some useful meta information * like minScn / maxScn across all the relays */ public RelayFindMaxSCNResult fetchMaxSCN(FetchMaxSCNRequest request) throws InterruptedException; /** * @note WARNING: For Databus internal use only * Applicable for Espresso internal replication only. * * Flush from available relays to be able to catch up with the highest SCN. * * Makes the Client point to the relays (specified in RelayFindMaxSCNResult) with the most recent sequence * number and waits (with timeout) for the consumer callback to reach this SCN. This is a * bounded blocking call. It will wait for timeout milliseconds for the consumer * callback to reach the maxScn before returning from this method * * @param fetchSCNResult : FetchMaxScn result object. * @param flushRequest : Request params for flush. */ public RelayFlushMaxSCNResult flush(RelayFindMaxSCNResult fetchSCNResult, FlushRequest flushRequest) throws InterruptedException; /** * @note WARNING: For Databus internal use only * Applicable for Espresso internal replication only. * * Discovers the most recent sequence number across all relays for the given subscriptions and uses flush * on the relay with that max SCN. This is a variant of the API call: * RelayFlushMaxSCNResult flush(RelayFindMaxSCNResult fetchSCNResult, FlushRequest flushRequest) * * @param FetchMaxSCNRequest : Request params for fetchMaxSCN. * @param flushRequest : Request params for flush. */ public RelayFlushMaxSCNResult flush(FetchMaxSCNRequest maxScnRequest, FlushRequest flushRequest) throws InterruptedException; /** * Retrieves the underlying registration id. * * Every registration (performed through a registerXXX call {@link DatabusHttpV3ClientImpl}) * is associated with a unique id. */ public RegistrationId getRegistrationId(); /** * @deprecated Please use {@link #getRegistrationId() instead} * @return */ @Deprecated public RegistrationId getId(); /** * The API methods below are not present in DatabusRegistration */ /** * Obtains the (Espresso) database name corresponding to this registration. * * A single registration cannot span more than one Espresso database. This method returns * the name of that unique database * * @throws IllegalStateException If this method is invoked on a parent registration ( which may have more than one database ) * */ public String getDBName() throws IllegalStateException; /** * Sets a listener interface for the client to get notified a partition is added / removed * Two use-cases are described below: * * Use-case 1: Manipulating a checkpoint for a partition * - The client creates a concrete implementation for DbusPartitionListener * - During the registration, it indicates that it wants to get notified before receiving events from a partition * - It invokes the registerCluster API as follows: * <pre> * {@code * registerCluster(clientClusterName, consumerFactory, source).withDbusV3PartitionListener(dbusV3PartitionListener); * } * </pre> * - After databus client gets notified by helix about partition assignment, the following callback is invoked * for the application * <pre> * {@code * dbusPartitionListener.onAddPartition(physicalPartition, databusV3Registration); * } * </pre> * - The checkpoint for the physicalPartition may be changed by invoking an api on child registration * databusV3Registration as follows * <pre> * {@code * databusV3Registration.storeCheckpoint(Checkpoint) * } * </pre> * * Use-case 2: Logging on the client * - The client is notified before a partition is added/dropped * - The physical partition and the child databus registration are given in the callback which may be logged * for informational purposes * */ public void withDbusV3PartitionListener(DbusV3PartitionListener dbus3PartitionListener) throws IllegalStateException; }