From e4c1988f9c1d16ecb8ba37115c24d943b1cf301a Mon Sep 17 00:00:00 2001 From: Nariman Abdullin Date: Mon, 11 Nov 2024 14:30:56 +0300 Subject: [PATCH] Supporting invalid path in BackupStorageUtils (#2989) * Supporting invalid path in BackupStorageUtils ### What's done: - backup storage utils expects ID in s3 path after a common prefix, it leads to number exception * self review * Add KDoc --------- Co-authored-by: Andrey Shcheglov --- .../common/storage/BackupStorageUtils.kt | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/common/src/jvmMain/kotlin/com/saveourtool/common/storage/BackupStorageUtils.kt b/common/src/jvmMain/kotlin/com/saveourtool/common/storage/BackupStorageUtils.kt index eadc90f3c9..d05f214f92 100644 --- a/common/src/jvmMain/kotlin/com/saveourtool/common/storage/BackupStorageUtils.kt +++ b/common/src/jvmMain/kotlin/com/saveourtool/common/storage/BackupStorageUtils.kt @@ -26,7 +26,7 @@ private val log = getLogger {} * * @param storageName * @param commonPrefix - * @param s3KeyValidator + * @param s3KeyValidator accepts S3 keys and returns `true` for **unexpected** ones. * @return [CompletableFuture] without body */ fun S3Operations.backupUnexpectedKeys( @@ -63,7 +63,7 @@ fun S3Operations.backupUnexpectedKeys( * * @param storageName * @param commonPrefix - * @param s3KeyValidator + * @param s3KeyValidator accepts S3 keys and returns `true` for **unexpected** ones. * @return [CompletableFuture] without body */ fun S3Operations.deleteUnexpectedKeys( @@ -95,9 +95,27 @@ fun S3Operations.deleteUnexpectedKeys( s3KeyValidator = s3KeyManager.asS3KeyValidator(), ) +/** + * @return the lambda, which accepts an _S3 key_ (in the form of `path/to/data/`) + * and returns `true` if the key is _invalid_. + */ private fun AbstractS3KeyDatabaseManager<*, *, *>.asS3KeyValidator(): (String) -> Boolean = { s3Key -> - val id = s3Key.removePrefix(commonPrefix).toLong() - findKeyByEntityId(id) == null + /*- + * S3 "folders", similarly to "files", also have keys. + * + * In our case, such a folder name may be the same as the prefix (e.g.: + * `path/to/data/`), that's why we use `toLongOrNull()` rather than + * `toLong()` here. + * + * The key to a folder which has the same name as the prefix (basically, + * the containing folder) is considered to be a *valid* key (the validator + * returning `false`). + */ + s3Key.removePrefix(commonPrefix) + .toLongOrNull() + ?.let { id -> + findKeyByEntityId(id) == null + } == true } private fun S3Operations.doBackupUnexpectedKeys( @@ -146,6 +164,9 @@ private fun S3Operations.doDeleteUnexpectedKeys( } } +/** + * @param s3KeyValidator accepts S3 keys and returns `true` for **unexpected** ones. + */ private fun S3Operations.detectUnexpectedKeys( commonPrefix: String, s3KeyValidator: (String) -> Boolean,