extract PooledBlockAllocatorProvider

GitOrigin-RevId: ac38d22d0707b30e67b2e3cf70f3408042e6cd98
This commit is contained in:
Vladimir Krivosheev
2019-06-09 22:08:27 +03:00
committed by intellij-monorepo-bot
parent f03c341b31
commit 569b3aa505
2 changed files with 92 additions and 89 deletions
@@ -4,23 +4,16 @@ package com.intellij.serialization
import com.amazon.ion.IonException
import com.amazon.ion.IonType
import com.amazon.ion.IonWriter
import com.amazon.ion.impl.bin.Block
import com.amazon.ion.impl.bin.BlockAllocator
import com.amazon.ion.impl.bin.BlockAllocatorProvider
import com.amazon.ion.impl.bin._Private_IonManagedBinaryWriterBuilder
import com.amazon.ion.system.IonReaderBuilder
import com.amazon.ion.system.IonTextWriterBuilder
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream
import com.intellij.util.ParameterizedTypeImpl
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.annotations.TestOnly
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.lang.reflect.Type
import java.nio.file.Path
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
import kotlin.experimental.or
private const val FORMAT_VERSION = 2
@@ -207,86 +200,4 @@ private fun createIonWriterBuilder(binary: Boolean, out: OutputStream): IonWrite
binary -> binaryWriterBuilder.newWriter(out)
else -> textWriterBuilder.build(out)
}
}
internal class PooledBlockAllocatorProvider : BlockAllocatorProvider() {
companion object {
// 512 KB
internal const val POOL_THRESHOLD = 512 * 1024
}
@Suppress("RemoveExplicitTypeArguments")
private val allocators = ContainerUtil.createConcurrentIntObjectMap<PooledBlockAllocator>()
private inner class PooledBlockAllocator(private val blockSize: Int) : BlockAllocator() {
private val freeBlocks = ArrayList<Block>()
private val blockCounter = AtomicInteger()
val byteSize: Int
get() = blockCounter.get() * blockSize
override fun allocateBlock(): Block {
val lastIndex = freeBlocks.lastIndex
if (lastIndex != -1) {
return freeBlocks.removeAt(lastIndex)
}
blockCounter.incrementAndGet()
return object : Block(ByteArray(blockSize)) {
override fun close() {
reset()
freeBlocks.add(this)
}
}
}
override fun getBlockSize() = blockSize
override fun close() {
if (allocators.putIfAbsent(blockSize, this) != null) {
// help GC - nullize
freeBlocks.clear()
blockCounter.set(0)
}
}
}
@get:TestOnly
val byteSize: Int
get() {
var totalByteSize = 0
for (allocator in allocators.elements()) {
totalByteSize += allocator.byteSize
}
return totalByteSize
}
override fun vendAllocator(blockSize: Int): BlockAllocator {
if (blockSize <= 0) {
throw IllegalArgumentException("Invalid block size: $blockSize")
}
// PooledBlockAllocator is not thread safe - do not put a new one to pool
val result = allocators.remove(blockSize) ?: PooledBlockAllocator(blockSize)
var totalByteSize = 0
val iterator = allocators.values().iterator()
var isExcess = false
while (iterator.hasNext()) {
val allocator = iterator.next()
if (isExcess) {
iterator.remove()
continue
}
totalByteSize += allocator.byteSize
if (totalByteSize > POOL_THRESHOLD) {
iterator.remove()
isExcess = true
}
}
return result
}
}
@@ -0,0 +1,92 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.serialization
import com.amazon.ion.impl.bin.Block
import com.amazon.ion.impl.bin.BlockAllocator
import com.amazon.ion.impl.bin.BlockAllocatorProvider
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.annotations.TestOnly
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
internal class PooledBlockAllocatorProvider : BlockAllocatorProvider() {
companion object {
// 512 KB
internal const val POOL_THRESHOLD = 512 * 1024
}
@Suppress("RemoveExplicitTypeArguments")
private val allocators = ContainerUtil.createConcurrentIntObjectMap<PooledBlockAllocator>()
private inner class PooledBlockAllocator(private val blockSize: Int) : BlockAllocator() {
private val freeBlocks = ArrayList<Block>()
private val blockCounter = AtomicInteger()
val byteSize: Int
get() = blockCounter.get() * blockSize
override fun allocateBlock(): Block {
val lastIndex = freeBlocks.lastIndex
if (lastIndex != -1) {
return freeBlocks.removeAt(lastIndex)
}
blockCounter.incrementAndGet()
return object : Block(ByteArray(blockSize)) {
override fun close() {
reset()
freeBlocks.add(this)
}
}
}
override fun getBlockSize() = blockSize
override fun close() {
if (allocators.putIfAbsent(blockSize, this) != null) {
// help GC - nullize
freeBlocks.clear()
blockCounter.set(0)
}
}
}
@get:TestOnly
val byteSize: Int
get() {
var totalByteSize = 0
for (allocator in allocators.elements()) {
totalByteSize += allocator.byteSize
}
return totalByteSize
}
override fun vendAllocator(blockSize: Int): BlockAllocator {
if (blockSize <= 0) {
throw IllegalArgumentException("Invalid block size: $blockSize")
}
// PooledBlockAllocator is not thread safe - do not put a new one to pool
val result = allocators.remove(blockSize) ?: PooledBlockAllocator(blockSize)
var totalByteSize = 0
val iterator = allocators.values().iterator()
var isExcess = false
while (iterator.hasNext()) {
val allocator = iterator.next()
if (isExcess) {
iterator.remove()
continue
}
totalByteSize += allocator.byteSize
if (totalByteSize > POOL_THRESHOLD) {
iterator.remove()
isExcess = true
}
}
return result
}
}