Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ghost element when applying multiples minus operations on a PersistentHashSet #144

Open
correacaio opened this issue Mar 28, 2023 · 0 comments
Labels

Comments

@correacaio
Copy link

Hi everyone.

We have been using kotlinx collections immutable for some years and we finally found a bug 😟
I don't know exactly why it happens, but I can simulate it with the following code:

(1..1000).forEach {   // the bug doesn't happen every time, so I put it inside a loop to make it easier to happen 
    val originalList = (1..40000)
        .map {
            listOf(
                UUID.randomUUID().toString(),
                UUID.randomUUID().toString()
            )
        }
    
    val originalPersistentSet = originalList.flatten()
        .toPersistentList()
        .add(UUID.randomUUID().toString())  // this is the only element that shouldn't be removed
        .toPersistentHashSet()
    
    val firstLBatchToRemove = originalList.map { it[0] }.toPersistentHashSet()
    val secondBatchToRemove = originalList.map { it[1] }.toPersistentHashSet()
    
    val result = originalPersistentSet
    //  .minus(firstLBatchToRemove.plus(secondBatchToRemove).toPersistentHashSet())  // if I use this line instead of the next two, it seems that the bug doesn't happen anymore
        .minus(firstLBatchToRemove)
        .minus(secondBatchToRemove)
        .toPersistentHashSet()
    
    result.size shouldBe 1  // always true, as it should be
    shouldNotThrowAny { println(result.first()) }    // This assert fails once in a while throwing `NoSuchElementException`
    
    delay(1.seconds)
}

Basically, after two minus operations in a "large" PersistentHashSet, I get a PersistentSet with size 1 (as expected in this test). Still, when I try to get the element, the following exception is thrown:

Collection is empty.
java.util.NoSuchElementException: Collection is empty.
	at kotlin.collections.CollectionsKt___CollectionsKt.first(_Collections.kt:201)
	at com.collections.PersistentHashSetTest$1$2.invokeSuspend(PersistentHashSetTest.kt:59) // my test class
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)

It long as I can tell, it is a bug exclusively on PersistentHashSet.
I've applied the same tests using PersistentSet, HashSet, and Lists (immutable or not) and it worked just fine.

Hope I have explained it successfully, please tell me if I can help more somehow.

@qurbonzoda qurbonzoda added the bug label Jun 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants