Skip to content

Commit cc78eb6

Browse files
Merge pull request #88 from target/getIntoOnHeapMemoryBuffer
Add NativeMemoryMap.getIntoOnHeapMemoryBuffer
2 parents 3a1ef6b + 4dd2f37 commit cc78eb6

4 files changed

Lines changed: 92 additions & 0 deletions

File tree

src/main/kotlin/com/target/nativememoryallocator/map/NativeMemoryMap.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.target.nativememoryallocator.map
22

33
import com.github.benmanes.caffeine.cache.stats.CacheStats
4+
import com.target.nativememoryallocator.buffer.NativeMemoryBuffer
45
import com.target.nativememoryallocator.buffer.NativeMemoryBufferMetadata
56
import com.target.nativememoryallocator.buffer.OnHeapMemoryBuffer
67

@@ -86,6 +87,13 @@ interface NativeMemoryMap<KEY_TYPE : Any, VALUE_TYPE : Any> : BaseNativeMemoryMa
8687
*/
8788
fun get(key: KEY_TYPE): VALUE_TYPE?
8889

90+
/**
91+
* Get a value from the map using the [key], copying the native memory contents into [onHeapMemoryBuffer].
92+
*
93+
* @return true if key was found and value copied into [onHeapMemoryBuffer], false otherwise.
94+
*/
95+
fun getIntoOnHeapMemoryBuffer(key: KEY_TYPE, onHeapMemoryBuffer: OnHeapMemoryBuffer): Boolean
96+
8997
/**
9098
* [Set] of [KEY_TYPE] for the map.
9199
*

src/main/kotlin/com/target/nativememoryallocator/map/impl/NativeMemoryMapImpl.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,20 @@ internal class NativeMemoryMapImpl<KEY_TYPE : Any, VALUE_TYPE : Any>(
126126
}
127127
}
128128

129+
override fun getIntoOnHeapMemoryBuffer(key: KEY_TYPE, onHeapMemoryBuffer: OnHeapMemoryBuffer): Boolean {
130+
var found = false
131+
132+
cacheMap.computeIfPresent(key) { _, currentBuffer ->
133+
found = true
134+
135+
currentBuffer.copyToOnHeapMemoryBuffer(onHeapMemoryBuffer = onHeapMemoryBuffer)
136+
137+
currentBuffer
138+
}
139+
140+
return found
141+
}
142+
129143
override val keys: Set<KEY_TYPE>
130144
get() = cacheMap.keys
131145

src/main/kotlin/com/target/nativememoryallocator/map/impl/OperationCountedNativeMemoryMapImpl.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.target.nativememoryallocator.map.impl
22

3+
import com.target.nativememoryallocator.buffer.OnHeapMemoryBuffer
34
import com.target.nativememoryallocator.map.NativeMemoryMap
45
import com.target.nativememoryallocator.map.NativeMemoryMapOperationCounters
56
import java.util.concurrent.atomic.AtomicLong
@@ -76,6 +77,23 @@ internal class OperationCountedNativeMemoryMapImpl<KEY_TYPE : Any, VALUE_TYPE :
7677
return getResult
7778
}
7879

80+
/**
81+
* Delegate to [NativeMemoryMap.getIntoOnHeapMemoryBuffer] and then update [operationCounters].
82+
*/
83+
override fun getIntoOnHeapMemoryBuffer(key: KEY_TYPE, onHeapMemoryBuffer: OnHeapMemoryBuffer): Boolean {
84+
val getResult = nativeMemoryMap.getIntoOnHeapMemoryBuffer(key = key, onHeapMemoryBuffer = onHeapMemoryBuffer)
85+
86+
operationCounters.apply {
87+
if (getResult) {
88+
numGetsNonNullValue.incrementAndGet()
89+
} else {
90+
numGetsNullValue.incrementAndGet()
91+
}
92+
}
93+
94+
return getResult
95+
}
96+
7997
/**
8098
* Delegate to [NativeMemoryMap.put] and then update [operationCounters].
8199
*/

src/test/kotlin/com/target/map/impl/NativeMemoryMapImplTest.kt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.target.map.impl
22

33
import com.target.nativememoryallocator.allocator.NativeMemoryAllocator
4+
import com.target.nativememoryallocator.allocator.NativeMemoryAllocatorBuilder
45
import com.target.nativememoryallocator.buffer.NativeMemoryBuffer
56
import com.target.nativememoryallocator.buffer.OnHeapMemoryBuffer
67
import com.target.nativememoryallocator.buffer.OnHeapMemoryBufferFactory
@@ -279,6 +280,7 @@ class NativeMemoryMapImplTest {
279280
}
280281
}
281282

283+
282284
@Test
283285
fun `test put reuse buffer`() {
284286
val serializedValue1 = ByteArray(10)
@@ -441,4 +443,54 @@ class NativeMemoryMapImplTest {
441443
mockNativeMemoryAllocator.freeNativeMemoryBuffer(buffer = mockNativeMemoryBuffer)
442444
}
443445
}
446+
447+
@Test
448+
fun `test put then getIntoOnHeapMemoryBuffer`() {
449+
450+
class NMAStringSerializer : NativeMemoryMapSerializer<String> {
451+
452+
override fun deserializeFromOnHeapMemoryBuffer(onHeapMemoryBuffer: OnHeapMemoryBuffer): String =
453+
String(
454+
onHeapMemoryBuffer.array, 0, onHeapMemoryBuffer.getReadableBytes()
455+
)
456+
457+
override fun serializeToByteArray(value: String): ByteArray = value.toByteArray()
458+
}
459+
460+
clearAllMocks()
461+
462+
val nativeMemoryAllocator = NativeMemoryAllocatorBuilder(
463+
pageSizeBytes = 1024,
464+
nativeMemorySizeBytes = 16 * 1024 * 1024, // 16 MB
465+
).build()
466+
467+
val testValue = "hello world"
468+
469+
val nativeMemoryMap = NativeMemoryMapImpl(
470+
valueSerializer = NMAStringSerializer(),
471+
nativeMemoryAllocator = nativeMemoryAllocator,
472+
useThreadLocalOnHeapReadBuffer = false,
473+
threadLocalOnHeapReadBufferInitialCapacityBytes = (256 * 1024),
474+
cacheMap = ConcurrentHashMap(),
475+
)
476+
477+
val putResult = nativeMemoryMap.put(key = 1, value = testValue)
478+
putResult shouldBe NativeMemoryMap.PutResult.ALLOCATED_NEW_BUFFER
479+
480+
val readOnHeapMemoryBuffer = OnHeapMemoryBufferFactory.newOnHeapMemoryBuffer(initialCapacityBytes = 1)
481+
482+
nativeMemoryMap.getIntoOnHeapMemoryBuffer(
483+
key = 1,
484+
onHeapMemoryBuffer = readOnHeapMemoryBuffer
485+
) shouldBe true
486+
487+
readOnHeapMemoryBuffer.getReadableBytes() shouldBe 11
488+
String(readOnHeapMemoryBuffer.toTrimmedArray(), 0, readOnHeapMemoryBuffer.getReadableBytes()) shouldBe testValue
489+
490+
nativeMemoryMap.getIntoOnHeapMemoryBuffer(key = 2, onHeapMemoryBuffer = readOnHeapMemoryBuffer) shouldBe false
491+
492+
nativeMemoryMap.keys shouldBe setOf(1)
493+
nativeMemoryMap.size shouldBe 1
494+
}
495+
444496
}

0 commit comments

Comments
 (0)