/src/main/scala/justin/db/JustinDB.scala

https://github.com/justin-db/JustinDB · Scala · 89 lines · 68 code · 16 blank · 5 comment · 0 complexity · 7d1cc8c0a494001d1bab6d621cab4d01 MD5 · raw file

  1. package justin.db
  2. import akka.actor.ActorSystem
  3. import akka.cluster.Cluster
  4. import akka.cluster.http.management.ClusterHttpManagement
  5. import akka.http.scaladsl.Http
  6. import akka.http.scaladsl.server.Directives._
  7. import akka.stream.{ActorMaterializer, Materializer}
  8. import buildinfo.BuildInfo
  9. import com.typesafe.scalalogging.StrictLogging
  10. import justin.db.actors.{StorageNodeActor, StorageNodeActorRef}
  11. import justin.db.client.ActorRefStorageNodeClient
  12. import justin.db.cluster.datacenter.Datacenter
  13. import justin.db.consistenthashing.{NodeId, Ring}
  14. import justin.db.replica.N
  15. import justin.db.storage.PluggableStorageProtocol
  16. import justin.db.storage.provider.StorageProvider
  17. import justin.httpapi.{BuildInfoRouter, HealthCheckRouter, HttpRouter}
  18. import scala.concurrent.duration._
  19. import scala.concurrent.{Await, ExecutionContext, Promise}
  20. import scala.language.reflectiveCalls
  21. // $COVERAGE-OFF$
  22. final class JustinDB
  23. object JustinDB extends StrictLogging {
  24. private[this] def validConfiguration(justinDBConfig: JustinDBConfig): Unit = {
  25. require(justinDBConfig.replication.N > 0, "replication N factor can't be smaller or equal 0")
  26. require(justinDBConfig.ring.`members-count` > 0, "members-counter can't be smaller or equal 0")
  27. require(justinDBConfig.ring.partitions > 0, "ring partitions can't be smaller or equal 0")
  28. require(justinDBConfig.ring.partitions >= justinDBConfig.ring.`members-count`, "number of ring partitions can't be smaller than number of members-count")
  29. require(justinDBConfig.replication.N <= justinDBConfig.ring.`members-count`, "replication N factor can't be bigger than defined members-count number")
  30. }
  31. private[this] def initStorage(justinConfig: JustinDBConfig) = {
  32. val provider = StorageProvider.apply(justinConfig.storage.provider)
  33. logger.info("Storage provider: " + provider.name)
  34. provider.init
  35. }
  36. def init(justinConfig: JustinDBConfig)(implicit actorSystem: ActorSystem): JustinDB = {
  37. validConfiguration(justinConfig)
  38. val processOrchestrator = Promise[JustinDB]
  39. implicit val executor: ExecutionContext = actorSystem.dispatcher
  40. implicit val materializer: Materializer = ActorMaterializer()
  41. val storage: PluggableStorageProtocol = initStorage(justinConfig)
  42. val cluster = Cluster(actorSystem)
  43. cluster.registerOnMemberUp {
  44. // STORAGE ACTOR
  45. val storageNodeActorRef = StorageNodeActorRef {
  46. val nodeId = NodeId(justinConfig.`kubernetes-hostname`.split("-").last.toInt)
  47. val ring = Ring(justinConfig.ring.`members-count`, justinConfig.ring.partitions)
  48. val n = N(justinConfig.replication.N)
  49. val datacenter = Datacenter(justinConfig.dc.`self-data-center`)
  50. actorSystem.actorOf(
  51. props = StorageNodeActor.props(nodeId, datacenter, storage, ring, n),
  52. name = StorageNodeActor.name(nodeId, datacenter)
  53. )
  54. }
  55. // AKKA-MANAGEMENT
  56. ClusterHttpManagement(cluster).start().map { _ =>
  57. logger.info("Cluster HTTP-Management is ready!")
  58. }.recover { case ex => processOrchestrator.failure(ex) }
  59. // HTTP API
  60. val routes = logRequestResult(actorSystem.name) {
  61. new HttpRouter(new ActorRefStorageNodeClient(storageNodeActorRef)).routes ~
  62. new HealthCheckRouter().routes ~
  63. new BuildInfoRouter().routes(BuildInfo.toJson)
  64. }
  65. Http()
  66. .bindAndHandle(routes, justinConfig.http.interface, justinConfig.http.port)
  67. .map { binding => logger.info(s"HTTP server started at ${binding.localAddress}"); processOrchestrator.trySuccess(new JustinDB) }
  68. .recover { case ex => logger.error("Could not start HTTP server", ex); processOrchestrator.failure(ex) }
  69. }
  70. Await.result(processOrchestrator.future, 2.minutes)
  71. }
  72. }
  73. // $COVERAGE-ON$