Skip to content

Commit 0d76ae4

Browse files
committed
fix(model-server): remove repository data after deletion
1 parent 563e21c commit 0d76ae4

File tree

4 files changed

+91
-4
lines changed

4 files changed

+91
-4
lines changed

model-server/src/main/kotlin/org/modelix/model/server/handlers/RepositoriesManager.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ class RepositoriesManager(val client: LocalModelClient) : IRepositoriesManager {
226226
}
227227

228228
override suspend fun removeRepository(repository: RepositoryId): Boolean {
229+
val genericStore = store.getGenericStore()
230+
229231
return store.runTransactionSuspendable {
230232
if (!repositoryExists(repository)) {
231233
return@runTransactionSuspendable false
@@ -234,12 +236,12 @@ class RepositoriesManager(val client: LocalModelClient) : IRepositoriesManager {
234236
for (branchName in getBranchNames(repository)) {
235237
putVersionHash(repository.getBranchReference(branchName), null)
236238
}
237-
store.getGenericStore().put(branchListKey(repository), null)
239+
genericStore.put(branchListKey(repository), null)
238240
val isolated = checkNotNull(isIsolated(repository)) { "Repository not found: $repository" }
239241
val existingRepositories = getRepositories(isolated)
240242
val remainingRepositories = existingRepositories - repository
241243
store.put(repositoriesListKey(isolated), remainingRepositories.joinToString("\n") { it.id })
242-
244+
genericStore.removeRepositoryObjects(repository)
243245
true
244246
}
245247
}

model-server/src/main/kotlin/org/modelix/model/server/store/IGenericStoreClient.kt

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,27 @@
1717
package org.modelix.model.server.store
1818

1919
import org.modelix.model.IGenericKeyListener
20+
import org.modelix.model.lazy.RepositoryId
2021

21-
typealias IsolatingStore = IGenericStoreClient<ObjectInRepository>
22+
/**
23+
* A store that saves data on a per-repository basis.
24+
* The primary key is of type [ObjectInRepository].
25+
*/
26+
interface IsolatingStore : IGenericStoreClient<ObjectInRepository> {
27+
/**
28+
* Default implementation for removing repository objects.
29+
* May be overridden by more efficient, store-specific implementations.
30+
*
31+
* Callers need to ensure that the repository is not usable anymore before calling this method.
32+
*/
33+
fun removeRepositoryObjects(repositoryId: RepositoryId) {
34+
val keysToDelete = getAll().asSequence()
35+
.map { it.key }
36+
.filter { it.getRepositoryId() == repositoryId.id }
37+
.toSet()
38+
putAll(keysToDelete.associateWith { null })
39+
}
40+
}
2241

2342
interface IGenericStoreClient<KeyT> : AutoCloseable {
2443
operator fun get(key: KeyT): String? = getAll(listOf(key)).first()

model-server/src/main/kotlin/org/modelix/model/server/store/InMemoryStoreClient.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,14 @@ class InMemoryStoreClient : IsolatingStore {
103103
try {
104104
transactionValues = HashMap()
105105
val result = body()
106-
values.putAll(transactionValues!!)
106+
val tValues = requireNotNull(transactionValues) { "Passed lambda set 'transactionValues' to null unexpectedly." }
107+
108+
val puts = tValues.filterValues { it != null }
109+
val deletes = tValues.filterValues { it == null }.keys
110+
values.putAll(puts)
111+
for (keyToDelete in deletes) {
112+
values.remove(keyToDelete)
113+
}
107114
result
108115
} finally {
109116
transactionValues = null
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package org.modelix.model.server.handlers
2+
3+
import kotlinx.coroutines.test.runTest
4+
import org.modelix.model.lazy.RepositoryId
5+
import org.modelix.model.server.store.IgniteStoreClient
6+
import org.modelix.model.server.store.InMemoryStoreClient
7+
import org.modelix.model.server.store.IsolatingStore
8+
import org.modelix.model.server.store.LocalModelClient
9+
import kotlin.test.AfterTest
10+
import kotlin.test.Test
11+
import kotlin.test.assertEquals
12+
import kotlin.test.assertTrue
13+
14+
class RepositoriesManagerWithInMemoryStoreClientTest : RepositoriesManagerTest(InMemoryStoreClient())
15+
class RepositoriesManagerWithIgniteStoreClientTest : RepositoriesManagerTest(IgniteStoreClient(inmemory = true))
16+
17+
abstract class RepositoriesManagerTest(val store: IsolatingStore) {
18+
protected val repoManager = RepositoriesManager(LocalModelClient(store))
19+
protected suspend fun initRepository(repoId: RepositoryId) {
20+
repoManager.createRepository(repoId, "testUser", useRoleIds = true, legacyGlobalStorage = false)
21+
}
22+
23+
@AfterTest
24+
fun cleanup() {
25+
store.close()
26+
}
27+
28+
@Test
29+
fun `repository data is removed when removing repository`() = runTest {
30+
val repoId = RepositoryId("abc")
31+
initRepository(repoId)
32+
33+
fun getRepositoryData() = store.getAll().filterKeys { it.getRepositoryId() == repoId.id }
34+
35+
val dataBeforeDeletion = getRepositoryData()
36+
repoManager.removeRepository(repoId)
37+
val dataAfterDeletion = getRepositoryData()
38+
39+
assertTrue(dataBeforeDeletion.isNotEmpty(), "Expected data to be present before deletion.")
40+
assertTrue(dataAfterDeletion.isEmpty(), "Leftover repository data was found after deletion. entries=${dataAfterDeletion.size}")
41+
}
42+
43+
@Test
44+
fun `data of other repositories remains intact when removing a repository`() = runTest {
45+
val existingRepo = RepositoryId("existing")
46+
val toBeDeletedRepo = RepositoryId("tobedeleted")
47+
initRepository(existingRepo)
48+
initRepository(toBeDeletedRepo)
49+
50+
fun getExistingRepositoryData() = store.getAll().filterKeys { it.getRepositoryId() == existingRepo.id }
51+
52+
val dataBeforeDeletion = getExistingRepositoryData()
53+
repoManager.removeRepository(toBeDeletedRepo)
54+
val dataAfterDeletion = getExistingRepositoryData()
55+
56+
assertTrue(dataBeforeDeletion.isNotEmpty(), "Expected repository data was not found.")
57+
assertEquals(dataBeforeDeletion, dataAfterDeletion, "Unexpected change in repository data.")
58+
}
59+
}

0 commit comments

Comments
 (0)