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

main.app.cash.backfila.client.misk.hibernate.PartitionProvider.kt Maven / Gradle / Ivy

Go to download

Backfila is a service that manages backfill state, calling into other services to do batched work.

The newest version!
package app.cash.backfila.client.misk.hibernate

import app.cash.backfila.client.misk.hibernate.internal.BoundingRangeStrategy
import app.cash.backfila.client.misk.hibernate.internal.UnshardedHibernateBoundingRangeStrategy
import app.cash.backfila.client.misk.hibernate.internal.VitessShardedBoundingRangeStrategy
import app.cash.backfila.client.misk.hibernate.internal.VitessSingleCursorBoundingRangeStrategy
import app.cash.backfila.protos.clientservice.PrepareBackfillRequest
import javax.persistence.Table
import misk.hibernate.DbEntity
import misk.hibernate.Session
import misk.hibernate.Transacter
import misk.hibernate.shards
import misk.hibernate.transaction
import misk.vitess.Keyspace
import misk.vitess.Shard

/**
 * Provides connectivity to a singleton database or a set of database shards.
 */
interface PartitionProvider {
  /**
   * Names the databases that will be connected with [transaction]. In a Vitess environment these
   * are the shard names.
   */
  fun names(request: PrepareBackfillRequest): List

  fun  transaction(partitionName: String, task: (Session) -> T): T

  fun , Pkey : Any> boundingRangeStrategy(): BoundingRangeStrategy
}

/**
 * A simple unsharded partition provider that uses a single Backfila partition. If you
 * are using a Vitess datasource you should almost certainly be using one of the Vitess partition
 * providers. [VitessShardedPartitionProvider] [VitessSingleCursorPartitionProvider]
 */
class UnshardedPartitionProvider(private val transacter: Transacter) : PartitionProvider {
  override fun names(request: PrepareBackfillRequest) = listOf("only")

  override fun  transaction(partitionName: String, task: (Session) -> T) =
    transacter.transaction(task)

  override fun , Pkey : Any> boundingRangeStrategy(): BoundingRangeStrategy {
    return UnshardedHibernateBoundingRangeStrategy(this)
  }
}

/**
 * A sharded partition provider that creates a backfila partition per Vitess shard. Since a cursor is
 * maintained for each shard separately, if entities are moved between shards it's possible they
 * will be missed by the backfill. Also at minimum one thread is used per shard since each shard
 * is its own partition. If your entities can move, or if you need to run this backfill slower
 * than one thread per shard, consider using [VitessSingleCursorPartitionProvider] instead.
 */
class VitessShardedPartitionProvider, Pkey : Any>(
  private val transacter: Transacter,
  backfill: HibernateBackfill,
) : PartitionProvider {
  private val keyspace = Keyspace(backfill.entityClass.java.getAnnotation(Table::class.java).schema)

  override fun names(request: PrepareBackfillRequest) = shards().map { it.name }

  override fun  transaction(partitionName: String, task: (Session) -> T) =
    transacter.transaction(Shard(keyspace, partitionName), task)

  override fun , Pkey : Any> boundingRangeStrategy(): BoundingRangeStrategy {
    return VitessShardedBoundingRangeStrategy(this)
  }

  private fun shards() = transacter.shards(keyspace)
}

/**
 * A partition provider that iterates over sharded vitess using a single cursor. This can only be
 * used if pkeys are unique across all shards, e.g. using a vitess sequence.
 *
 * Prefer [VitessShardedPartitionProvider]
 *
 * The benefits of this vs [VitessShardedPartitionProvider] is that if entities move from one
 * customer to another, they will not be missed because one shard's cursor cannot get ahead of
 * another's. It is also indifferent to shard splits and can run slower than one thread per shard.
 * The disadvantage is less efficient concurrency, since batches are computed by scanning all shards
 * each time, rather than splitting the work by shard.
 */
class VitessSingleCursorPartitionProvider, Pkey : Any>(
  private val transacter: Transacter,
  backfill: HibernateBackfill,
) : PartitionProvider {
  private val keyspace = Keyspace(backfill.entityClass.java.getAnnotation(Table::class.java).schema)

  override fun names(request: PrepareBackfillRequest) = listOf("only")

  override fun  transaction(partitionName: String, task: (Session) -> T) =
    transacter.transaction(task)

  override fun , Pkey : Any> boundingRangeStrategy(): BoundingRangeStrategy {
    return VitessSingleCursorBoundingRangeStrategy(transacter, keyspace)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy