All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ebay.jetstream.event.processor.loadbalance.PartitionedLoadBalancer Maven / Gradle / Ivy

/*******************************************************************************
 *  Copyright © 2012-2015 eBay Software Foundation
 *  This program is dual licensed under the MIT and Apache 2.0 licenses.
 *  Please see LICENSE for more information.
 *******************************************************************************/

package com.ebay.jetstream.event.processor.loadbalance;

/**
*
* This component provides an implementation of a Load Balancer which distributes the events to its sinks in
* a partitioned scheme. A list of keys from the event can be used to create a partition key. A hash of
* the composite key mod num sinks determines the sink to schedule the event to. 
* 
* @author [email protected]
*
*/

import java.util.Collection;

import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.jmx.export.annotation.ManagedResource;

import com.ebay.jetstream.config.ContextBeanChangedEvent;
import com.ebay.jetstream.event.EventException;
import com.ebay.jetstream.event.EventSink;
import com.ebay.jetstream.event.JetstreamEvent;
import com.ebay.jetstream.event.support.AbstractEventProcessor;
import com.ebay.jetstream.management.Management;
import com.ebay.jetstream.xmlser.XSerializable;

@ManagedResource(objectName = "Event/Processor", description = "Load Balancer for balancing event traffic amongst sinks")
public class PartitionedLoadBalancer  extends AbstractEventProcessor implements XSerializable {

	private static final Logger LOGGER = LoggerFactory.getLogger("com.ebay.jetstream.event.processor.loadbalance");

	private int m_numSinks = -1;
	private EventSink[] m_sinks = new EventSink[20];
	private PartionedLoadBalancerConfig m_config;
	
	
	public PartionedLoadBalancerConfig getConfig() {
		return m_config;
	}

	public void setConfig(PartionedLoadBalancerConfig config) {
		this.m_config = config;
	}

				
	@Override
	public void sendEvent(JetstreamEvent event) throws EventException {
		
		incrementEventRecievedCounter();
		
		if (getConfig().getPartitionKeys().isEmpty()) {
			incrementEventDroppedCounter();
			return;
		}
		
		if (m_numSinks != getEventSinks().size()) {
			
			Collection sinks = getEventSinks();
			sinks.toArray(m_sinks);
			m_numSinks = sinks.size();
					
		}
		
		int pos = 0;
		
		if (m_numSinks > 0) {
			
			try {
				long hash = genHash(event);
				if (hash < 0)
					hash *= -1;
				
				pos = (int) (hash % m_numSinks);
			} catch (Exception e) {
				if (LOGGER.isDebugEnabled())
					LOGGER.debug("Failed to generate Hash - " + e.getLocalizedMessage());
				incrementEventDroppedCounter();
				return;
			}
			
			m_sinks[pos].sendEvent(event);
			incrementEventSentCounter();
		}
		
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		
		Management.removeBeanOrFolder(getBeanName(), this);
		Management.addBean(getBeanName(), this);
				
		Collection sinks = getEventSinks();
		sinks.toArray(m_sinks);
		m_numSinks = sinks.size();
		
	}

	@Override
	public int getPendingEvents() {
		return 0;
	}

	@Override
	public void shutDown() {
		
		
	}

	@Override
	public void pause() {
		
		if (isPaused()) {
			LOGGER.warn( getBeanName() + " could not be resumed. It is already in paused state");
			return;
		}
		
		changeState(ProcessorOperationState.PAUSE);
	}

	@Override
	protected void processApplicationEvent(ApplicationEvent event) {
		if (event instanceof ContextBeanChangedEvent) {
			ContextBeanChangedEvent bcInfo = (ContextBeanChangedEvent) event;
			// Calculate changes
			if (bcInfo.isChangedBean(getConfig())) {
				PartionedLoadBalancerConfig newConfig = (PartionedLoadBalancerConfig) bcInfo.getChangedBean(); 
				setConfig(newConfig);
				
			}
		}
	}

	@Override
	public void resume() {
		
		if (!isPaused()) {
		      LOGGER.warn( getBeanName() + " could not be resumed. It is already in resumed state");
	   	      return;
		}
		
		changeState(ProcessorOperationState.RESUME);
		
	}
	
	private long genHash(JetstreamEvent event) throws Exception {
		
		List partitionfields = getConfig().getPartitionFields(event.getEventType());
		
		if (partitionfields == null)
			throw new RuntimeException("could not find fields for event type : " + event.getEventType());
		
		long hash = 0;
		
		for (String key : partitionfields) {
			hash += (31 * event.get(key).hashCode());
		}
						
		return hash;
			
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy