mirror of
https://github.com/corda/corda.git
synced 2025-06-18 15:18:16 +00:00
CORDA-3755: Switched attachments map to a WeakHashMap (#6214)
* Bump OS release version 4.6 * CORDA-3755: Switched attachments map to a WeakHashMap * CORDA-3755: Added explicit strong references to map key. * CORDA-3755: Keeping detekt happy. * CORDA-3755: Test a gc in verify. * CORDA-3755: Making detekt happy. * CORDA-3755: Suppress warnings for weak reference test. * CORDA-3755: Fixing build failure with attachments. * CORDA-3755: Rewrite based on Ricks input - now handles attachment already existing in map! * CORDA-3755: Refactor WeakReference behaviour into AttachmentsHolderImpl and provide alternate version of this class for core-deterministic. * CORDA-3755: Added more tests for WeakHashMap. * CORDA-3755: Ignore the tests using System.gc keep for local testing only * CORDA-3755: Adding comment to explain the ignored tests. * Make AttachmentsHolderImpl package-private inside core-deterministic, just like it is inside core. * CORDA-3755: Update assertions following review comments. * CORDA-3755: Removing import * CORDA-3755: Removed unused var. * CORDA-3755: Reverting files that somehow got changed in rebase. Co-authored-by: nargas-ritu <ritu.gupta@r3.com> Co-authored-by: Chris Rankin <chris.rankin@r3.com>
This commit is contained in:
@ -5,13 +5,20 @@ import net.corda.core.contracts.ContractAttachment
|
||||
import net.corda.core.contracts.ContractClassName
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.services.AttachmentId
|
||||
import net.corda.core.serialization.internal.AttachmentURLStreamHandlerFactory
|
||||
import net.corda.core.serialization.internal.AttachmentsClassLoader
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertSame
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.lang.ref.ReferenceQueue
|
||||
import java.lang.ref.WeakReference
|
||||
import java.net.URL
|
||||
import java.net.URLClassLoader
|
||||
import java.security.PublicKey
|
||||
import java.util.jar.JarOutputStream
|
||||
@ -120,9 +127,125 @@ class ClassLoadingUtilsTest {
|
||||
}
|
||||
}
|
||||
|
||||
private fun signedAttachment(data: ByteArray, vararg parties: Party) = ContractAttachment.create(
|
||||
@Ignore("Using System.gc in this test which has no guarantees when/if gc occurs.")
|
||||
@Test(timeout=300_000)
|
||||
@Suppress("ExplicitGarbageCollectionCall", "UNUSED_VALUE")
|
||||
fun `test weak reference removed from map`() {
|
||||
val jarData = with(ByteArrayOutputStream()) {
|
||||
val internalName = STANDALONE_CLASS_NAME.asInternalName
|
||||
JarOutputStream(this, Manifest()).use {
|
||||
it.setLevel(NO_COMPRESSION)
|
||||
it.setMethod(DEFLATED)
|
||||
it.putNextEntry(directoryEntry("com"))
|
||||
it.putNextEntry(directoryEntry("com/example"))
|
||||
it.putNextEntry(classEntry(internalName))
|
||||
it.write(TemplateClassWithEmptyConstructor::class.java.renameTo(internalName))
|
||||
}
|
||||
toByteArray()
|
||||
}
|
||||
val attachment = signedAttachment(jarData)
|
||||
var url: URL? = AttachmentURLStreamHandlerFactory.toUrl(attachment)
|
||||
|
||||
val referenceQueue: ReferenceQueue<URL> = ReferenceQueue()
|
||||
val weakReference = WeakReference<URL>(url, referenceQueue)
|
||||
|
||||
assertEquals(1, AttachmentURLStreamHandlerFactory.loadedAttachmentsSize())
|
||||
// Clear strong reference
|
||||
url = null
|
||||
System.gc()
|
||||
val ref = referenceQueue.remove(100000)
|
||||
assertSame(weakReference, ref)
|
||||
assertEquals(0, AttachmentURLStreamHandlerFactory.loadedAttachmentsSize())
|
||||
}
|
||||
|
||||
@Ignore("Using System.gc in this test which has no guarantees when/if gc occurs.")
|
||||
@Test(timeout=300_000)
|
||||
@Suppress("ExplicitGarbageCollectionCall", "UNUSED_VALUE")
|
||||
fun `test adding same attachment twice then removing`() {
|
||||
val jarData = with(ByteArrayOutputStream()) {
|
||||
val internalName = STANDALONE_CLASS_NAME.asInternalName
|
||||
JarOutputStream(this, Manifest()).use {
|
||||
it.setLevel(NO_COMPRESSION)
|
||||
it.setMethod(DEFLATED)
|
||||
it.putNextEntry(directoryEntry("com"))
|
||||
it.putNextEntry(directoryEntry("com/example"))
|
||||
it.putNextEntry(classEntry(internalName))
|
||||
it.write(TemplateClassWithEmptyConstructor::class.java.renameTo(internalName))
|
||||
}
|
||||
toByteArray()
|
||||
}
|
||||
val attachment1 = signedAttachment(jarData)
|
||||
val attachment2 = signedAttachment(jarData)
|
||||
var url1: URL? = AttachmentURLStreamHandlerFactory.toUrl(attachment1)
|
||||
var url2: URL? = AttachmentURLStreamHandlerFactory.toUrl(attachment2)
|
||||
|
||||
val referenceQueue1: ReferenceQueue<URL> = ReferenceQueue()
|
||||
val weakReference1 = WeakReference<URL>(url1, referenceQueue1)
|
||||
|
||||
val referenceQueue2: ReferenceQueue<URL> = ReferenceQueue()
|
||||
val weakReference2 = WeakReference<URL>(url2, referenceQueue2)
|
||||
|
||||
assertEquals(1, AttachmentURLStreamHandlerFactory.loadedAttachmentsSize())
|
||||
url1 = null
|
||||
System.gc()
|
||||
val ref1 = referenceQueue1.remove(500)
|
||||
assertNull(ref1)
|
||||
assertEquals(1, AttachmentURLStreamHandlerFactory.loadedAttachmentsSize())
|
||||
|
||||
url2 = null
|
||||
System.gc()
|
||||
val ref2 = referenceQueue2.remove(100000)
|
||||
assertSame(weakReference2, ref2)
|
||||
assertSame(weakReference1, referenceQueue1.poll())
|
||||
assertEquals(0, AttachmentURLStreamHandlerFactory.loadedAttachmentsSize())
|
||||
}
|
||||
|
||||
@Ignore("Using System.gc in this test which has no guarantees when/if gc occurs.")
|
||||
@Test(timeout=300_000)
|
||||
@Suppress("ExplicitGarbageCollectionCall", "UNUSED_VALUE")
|
||||
fun `test adding two different attachments then removing`() {
|
||||
val jarData1 = with(ByteArrayOutputStream()) {
|
||||
val internalName = STANDALONE_CLASS_NAME.asInternalName
|
||||
JarOutputStream(this, Manifest()).use {
|
||||
it.setLevel(NO_COMPRESSION)
|
||||
it.setMethod(DEFLATED)
|
||||
it.putNextEntry(directoryEntry("com"))
|
||||
it.putNextEntry(directoryEntry("com/example"))
|
||||
it.putNextEntry(classEntry(internalName))
|
||||
it.write(TemplateClassWithEmptyConstructor::class.java.renameTo(internalName))
|
||||
}
|
||||
toByteArray()
|
||||
}
|
||||
|
||||
val attachment1 = signedAttachment(jarData1)
|
||||
val attachment2 = signedAttachment(jarData1, id = SecureHash.randomSHA256())
|
||||
var url1: URL? = AttachmentURLStreamHandlerFactory.toUrl(attachment1)
|
||||
var url2: URL? = AttachmentURLStreamHandlerFactory.toUrl(attachment2)
|
||||
|
||||
val referenceQueue1: ReferenceQueue<URL> = ReferenceQueue()
|
||||
val weakReference1 = WeakReference<URL>(url1, referenceQueue1)
|
||||
|
||||
val referenceQueue2: ReferenceQueue<URL> = ReferenceQueue()
|
||||
val weakReference2 = WeakReference<URL>(url2, referenceQueue2)
|
||||
|
||||
assertEquals(2, AttachmentURLStreamHandlerFactory.loadedAttachmentsSize())
|
||||
url1 = null
|
||||
System.gc()
|
||||
val ref1 = referenceQueue1.remove(100000)
|
||||
assertSame(weakReference1, ref1)
|
||||
assertEquals(1, AttachmentURLStreamHandlerFactory.loadedAttachmentsSize())
|
||||
|
||||
url2 = null
|
||||
System.gc()
|
||||
val ref2 = referenceQueue2.remove(100000)
|
||||
assertSame(weakReference2, ref2)
|
||||
assertEquals(0, AttachmentURLStreamHandlerFactory.loadedAttachmentsSize())
|
||||
}
|
||||
|
||||
private fun signedAttachment(data: ByteArray, id: AttachmentId = contractAttachmentId,
|
||||
vararg parties: Party) = ContractAttachment.create(
|
||||
object : AbstractAttachment({ data }, "test") {
|
||||
override val id: SecureHash get() = contractAttachmentId
|
||||
override val id: SecureHash get() = id
|
||||
|
||||
override val signerKeys: List<PublicKey> get() = parties.map(Party::owningKey)
|
||||
}, PROGRAM_ID, signerKeys = parties.map(Party::owningKey)
|
||||
|
Reference in New Issue
Block a user