Skip to content

Commit

Permalink
fix backup
Browse files Browse the repository at this point in the history
  • Loading branch information
asad-awadia committed Mar 8, 2022
1 parent ddb8c61 commit 594e325
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 23 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,5 +155,5 @@ Connect to `/ws/v1/:apiKey` to get updates about puts and deletes
## Auth

If `enable_auth` environment variable is set then the value of `api_key` environment variable is
used as the api key. The api key must be passed in as the `x-api-key` header value
used as the api key. The api key must be passed in as the `Authorization` header value with `Bearer ` as the prefix
If `api_key` is blank then the default key is admin [`enable_auth` must still be true]
13 changes: 12 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
<jvm.flags>-Xms:1g -Xmx:1g</jvm.flags>
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
</properties>

<dependencies>
Expand Down Expand Up @@ -84,6 +85,16 @@
<artifactId>xodus-crypto</artifactId>
<version>${xodus.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test-junit</artifactId>
Expand All @@ -109,7 +120,7 @@
<version>1.8.0</version>
<configuration>
<from>
<image>adoptopenjdk:16.0.1_9-jre-openj9-0.26.0-focal</image>
<image>ibm-semeru-runtimes:open-16-jre</image>
</from>
<to>
<image>kvdb</image>
Expand Down
28 changes: 20 additions & 8 deletions src/main/kotlin/dev/aawadia/Datastore.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,31 @@ import jetbrains.exodus.ArrayByteIterable
import jetbrains.exodus.bindings.StringBinding
import jetbrains.exodus.env.*
import jetbrains.exodus.util.CompressBackupUtil
import java.io.ByteArrayOutputStream
import java.io.File
import java.nio.charset.StandardCharsets.UTF_8
import java.util.concurrent.ConcurrentSkipListMap
import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream

class Datastore(
private val dbDir: String = "./db",
private val ssdtable: Environment = Environments.newInstance(dbDir, getEnvConfig()),
private val memtable: ConcurrentSkipListMap<String, String> = ConcurrentSkipListMap(),
private val store: String = "datastore",
private val ssdtable: Environment = Environments.newInstance(dbDir, getEnvConfig()),
private val memtable: ConcurrentSkipListMap<String, ByteArray> = ConcurrentSkipListMap()
) {
init {
populateMemtable()
}

fun get(key: String): String = memtable[key] ?: ""
fun getKeyRange(from: String, to: String) = memtable.subMap(from, to) ?: emptyMap()
fun get(key: String): String = memtable[key]?.ungzip() ?: ""
fun getKeyRange(from: String, to: String) = memtable.subMap(from, to).mapValues { it.value.ungzip() }

fun insert(key: String, value: String) {
ssdtable.executeInTransaction {
getStore(it).put(it, key.toByteIterable(), value.toByteIterable())
}
memtable[key] = value
memtable[key] = value.gzip()
}

fun delete(key: String) {
Expand All @@ -47,11 +51,11 @@ class Datastore(
}

private fun populateMemtable() {
memtable["init.ts"] = System.currentTimeMillis().toString()
memtable["init.ts"] = System.currentTimeMillis().toString().gzip()
ssdtable.executeInTransaction {
getStore(it).openCursor(it).use { cursor ->
while (cursor.next) {
memtable[StringBinding.entryToString(cursor.key)] = StringBinding.entryToString(cursor.value)
memtable[StringBinding.entryToString(cursor.key)] = StringBinding.entryToString(cursor.value).gzip()
}
}
}
Expand All @@ -61,4 +65,12 @@ class Datastore(
ssdtable.openStore(store, StoreConfig.WITHOUT_DUPLICATES_WITH_PREFIXING, transaction)
}

private fun String.toByteIterable(): ArrayByteIterable = StringBinding.stringToEntry(this)
private fun String.toByteIterable(): ArrayByteIterable = StringBinding.stringToEntry(this)

fun String.gzip(): ByteArray {
val bos = ByteArrayOutputStream()
GZIPOutputStream(bos).bufferedWriter(UTF_8).use { it.write(this) }
return bos.toByteArray()
}

fun ByteArray.ungzip(): String = GZIPInputStream(this.inputStream()).bufferedReader(UTF_8).use { it.readText() }
29 changes: 16 additions & 13 deletions src/main/kotlin/dev/aawadia/KVStoreServer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ package dev.aawadia

import io.micrometer.prometheus.PrometheusMeterRegistry
import io.vertx.core.AbstractVerticle
import io.vertx.core.Future
import io.vertx.core.http.HttpServerOptions
import io.vertx.core.http.ServerWebSocket
import io.vertx.core.json.JsonObject
import io.vertx.ext.auth.authentication.TokenCredentials
import io.vertx.ext.web.Router
import io.vertx.ext.web.RoutingContext
import io.vertx.ext.web.handler.*
Expand Down Expand Up @@ -40,7 +38,7 @@ class KVStoreServer(

vertx.createHttpServer(getHttpServerOptions())
.requestHandler(router)
.exceptionHandler { logger.warning(it.message) }
.exceptionHandler { it.printStackTrace() }
.listen(config().getInteger("port", 9090))
.onFailure { logger.warning(it.message) }
.onSuccess { logger.info("server started on port " + it.actualPort()) }
Expand All @@ -50,9 +48,8 @@ class KVStoreServer(
val response = JsonObject()
routingContext.queryParam("keys").first()
.split(",")
.forEach {
response.put(it, ds.get(it))
}
.forEach { response.put(it, ds.get(it)) }

routingContext.response()
.putHeader("Content-type", "application/json; charset=utf-8")
.end(response.encodePrettily())
Expand Down Expand Up @@ -151,16 +148,22 @@ class KVStoreServer(
}

private fun authMiddleware(router: Router) {
val apiKeyAuth = apiKeyAuth()
router.route("/kv*").handler(apiKeyAuth)
router.route("/admin*").handler(apiKeyAuth)
router.route("/kv*").handler(this::bearerAuth)
router.route("/admin*").handler(this::bearerAuth)
}

private fun apiKeyAuth(): APIKeyHandler {
return APIKeyHandler.create { credentials, resultHandler ->
val keyMatch = credentials.mapTo(TokenCredentials::class.java).token == getApiKey()
if (keyMatch) resultHandler.handle(Future.succeededFuture()) else resultHandler.handle(Future.failedFuture("invalid api key provided"))
private fun bearerAuth(routingContext: RoutingContext) {
if (!routingContext.request().headers().contains("Authorization")) {
routingContext.fail(403, IllegalAccessException())
return
}
val authHeader = routingContext.request().getHeader("Authorization").ifEmpty { "Bearer " }
val split = authHeader.split("Bearer ")
if (split.size != 2 || split[1] != getApiKey()) {
routingContext.fail(403, IllegalAccessException())
return
}
routingContext.next()
}

private fun getApiKey(): String {
Expand Down

0 comments on commit 594e325

Please sign in to comment.