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

com.cj.kafka.rx.ZookeeperOffsetCommitter.scala Maven / Gradle / Ivy

The newest version!
package com.cj.kafka.rx

import com.google.common.base.Charsets
import org.apache.curator.framework.CuratorFramework
import org.apache.curator.framework.imps.CuratorFrameworkState
import org.apache.curator.framework.recipes.locks.InterProcessMutex
import org.apache.curator.utils.ZKPaths

class ZookeeperLock(zk: CuratorFramework, path: String) extends PartitionLock {
  val lock = new InterProcessMutex(zk, path)
  def acquire(): Unit = lock.acquire()
  def release(): Unit = lock.release()
}

class ZookeeperOffsetCommitter(group: String, zk: CuratorFramework) extends OffsetCommitter with SynchronizedCommitter {

  def getPartitionPath(topic: String, part: Int) =
    ZKPaths.makePath(s"/consumers/$group/offsets/$topic", part.toString)

  override def start() = {
    if (zk.getState != CuratorFrameworkState.STARTED) {
      zk.start()
      zk.blockUntilConnected()
    }
  }

  override def stop() = zk.close()

  def getOffsets(topicPartitions: Iterable[TopicPartition]): OffsetMap = {
     topicPartitions.flatMap { topicPartition =>
       val (topic, partition) = topicPartition
       val path = getPartitionPath(topic, partition)
       Option(zk.checkExists.forPath(path)) match {
         case None => List()
         case Some(filestats) =>
           val bytes = zk.getData.forPath(path)
           val str = new String(bytes, Charsets.UTF_8).trim
           val offset = java.lang.Long.parseLong(str)
           List(topicPartition -> offset)
       }
     }.toMap
  }

  def setOffsets(offsets: OffsetMap): OffsetMap = {
    offsets foreach { case (topicPartition, offset) =>
      val (topic,partition) = topicPartition
      val nodePath = getPartitionPath(topic, partition)
      val bytes = offset.toString.getBytes(Charsets.UTF_8)
      Option(zk.checkExists.forPath(nodePath)) match {
        case None =>
          zk.create.creatingParentsIfNeeded.forPath(nodePath, bytes)
        case Some(fileStats) =>
          zk.setData().forPath(nodePath, bytes)
      }
    }
    getOffsets(offsets.keys)
  }

  def getPartitionLock(topicPartition:TopicPartition) : PartitionLock = {
    val (topic,partition) = topicPartition
    val lockPath = s"/locks/kafka-rx/$topic.$group.$partition"
    new ZookeeperLock(zk, lockPath)
  }

  def commit(offsets: OffsetMap, merge: OffsetMerge): OffsetMap = {
    withPartitionLocks(offsets.keys) {
      val zkOffsets = getOffsets(offsets.keys)
      val nextOffsets = merge(zkOffsets, offsets) map { case (topicPartition, offset) =>
        // zookeeper stores the *next* offset
        // while kafka messages contain their offset, shift forward 1 for zk format
        topicPartition -> (offset + 1)
      }
      setOffsets(nextOffsets)
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy