将AdvanceByteBuffer替换为更加简洁的ByteBuffer

This commit is contained in:
tursom 2019-11-20 13:09:30 +08:00
parent be04d7ff73
commit 75483b45a1
107 changed files with 3245 additions and 2419 deletions

View File

@ -0,0 +1,55 @@
package cn.tursom.niothread
import java.io.Closeable
import java.nio.channels.SelectableChannel
import java.nio.channels.SelectionKey
import java.nio.channels.Selector
import java.util.concurrent.Callable
/**
* 一个 nio 工作线程
* 一个线程对应一个 Selector 选择器
*/
interface NioThread : Closeable {
val selector: Selector
val closed: Boolean
val timeout: Long
val workLoop: (thread: NioThread, key: SelectionKey) -> Unit
val thread: Thread
val daemon: Boolean
fun wakeup() {
if (Thread.currentThread() != thread) selector.wakeup()
}
/**
* 将通道注册到线程对应的选择器上
*/
fun register(channel: SelectableChannel, ops: Int, onComplete: (key: SelectionKey) -> Unit) {
if (Thread.currentThread() == thread) {
val key = channel.register(selector, ops)
onComplete(key)
} else {
execute {
val key = channel.register(selector, ops)
onComplete(key)
}
wakeup()
}
}
fun execute(command: Runnable) = execute(command::run)
fun execute(command: () -> Unit)
fun <T> call(task: Callable<T>): T {
return submit(task).get()
}
fun <T> call(task: () -> T): T {
return call(Callable<T> { task() })
}
fun <T> submit(task: Callable<T>): NioThreadTaskFuture<T> = submit(task::call)
fun <T> submit(task: () -> T): NioThreadTaskFuture<T>
}

View File

@ -0,0 +1,5 @@
package cn.tursom.niothread
interface NioThreadTaskFuture<T> {
fun get(): T
}

View File

@ -0,0 +1,78 @@
package cn.tursom.niothread
import java.nio.channels.SelectableChannel
import java.nio.channels.SelectionKey
import java.nio.channels.Selector
import java.util.concurrent.*
@Suppress("MemberVisibilityCanBePrivate")
class ThreadPoolNioThread(
val threadName: String = "",
override val selector: Selector = Selector.open(),
override val daemon: Boolean = false,
override val timeout: Long = 3000,
override val workLoop: (thread: NioThread, key: SelectionKey) -> Unit
) : NioThread {
override lateinit var thread: Thread
val threadPool: ExecutorService = ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
LinkedBlockingQueue<Runnable>(),
ThreadFactory {
val thread = Thread(it)
this.thread = thread
thread.isDaemon = daemon
thread.name = threadName
thread
})
override var closed: Boolean = false
init {
threadPool.execute(object : Runnable {
override fun run() {
if (selector.isOpen) {
if (selector.select(timeout) != 0) {
val keyIter = selector.selectedKeys().iterator()
while (keyIter.hasNext()) {
val key = keyIter.next()
keyIter.remove()
workLoop(this@ThreadPoolNioThread, key)
}
}
}
if (!threadPool.isShutdown) threadPool.execute(this)
}
})
}
override fun wakeup() {
if (Thread.currentThread() != thread) {
selector.wakeup()
}
}
override fun register(channel: SelectableChannel, ops: Int, onComplete: (key: SelectionKey) -> Unit) {
if (Thread.currentThread() == thread) {
onComplete(channel.register(selector, ops))
} else {
threadPool.execute { register(channel, ops, onComplete) }
wakeup()
}
}
override fun execute(command: () -> Unit) = threadPool.execute(command)
override fun <T> call(task: Callable<T>): T = threadPool.submit(task).get()
override fun <T> submit(task: () -> T): NioThreadTaskFuture<T> = ThreadPoolTaskFuture(threadPool.submit(task))
override fun close() {
closed = true
threadPool.shutdown()
}
class ThreadPoolTaskFuture<T>(val future: Future<T>) : NioThreadTaskFuture<T> {
override fun get(): T = future.get()
}
override fun toString(): String {
return "SingleThreadNioThread($threadName)"
}
}

View File

@ -0,0 +1,113 @@
package cn.tursom.niothread
import cn.tursom.core.NonLockLinkedList
import java.nio.channels.SelectionKey
import java.nio.channels.Selector
@Suppress("MemberVisibilityCanBePrivate", "CanBeParameter")
class WorkerLoopNioThread(
val threadName: String = "nioLoopThread",
override val selector: Selector = Selector.open(),
override val daemon: Boolean = false,
override val timeout: Long = 3000,
override val workLoop: (thread: NioThread, key: SelectionKey) -> Unit
) : NioThread {
override var closed: Boolean = false
val waitQueue = NonLockLinkedList<() -> Unit>()
//val taskQueue = LinkedBlockingDeque<Future<Any?>>()
override val thread = Thread {
while (!closed) {
try {
if (selector.isOpen) {
if (selector.select(timeout) != 0) {
val keyIter = selector.selectedKeys().iterator()
while (keyIter.hasNext()) {
val key = keyIter.next()
keyIter.remove()
workLoop(this, key)
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
while (true) try {
(waitQueue.take() ?: break)()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
init {
thread.name = threadName
thread.isDaemon = daemon
thread.start()
}
override fun execute(command: () -> Unit) {
waitQueue.add(command)
}
override fun <T> submit(task: () -> T): NioThreadTaskFuture<T> {
val f = Future<T>()
waitQueue {
try {
f.resume(task())
} catch (e: Throwable) {
f.resumeWithException(e)
}
}
return f
}
override fun close() {
closed = true
}
override fun wakeup() {
if (Thread.currentThread() != thread) {
selector.wakeup()
}
}
class Future<T> : NioThreadTaskFuture<T> {
private val lock = Object()
private var exception: Throwable? = null
private var result: T? = null
@Throws(Throwable::class)
override fun get(): T {
val result = this.result
return when {
exception != null -> throw exception as Throwable
result != null -> result
else -> synchronized(lock) {
lock.wait()
val exception = this.exception
if (exception != null) {
throw exception
} else {
this.result!!
}
}
}
}
fun resume(value: T) {
result = value
synchronized(lock) {
lock.notifyAll()
}
}
fun resumeWithException(e: Throwable) {
exception = e
synchronized(lock) {
lock.notifyAll()
}
}
}
}

View File

@ -0,0 +1,35 @@
package cn.tursom.niothread.loophandler
import cn.tursom.niothread.NioThread
import cn.tursom.socket.NioProtocol
import java.nio.channels.SelectionKey
import java.nio.channels.ServerSocketChannel
class BossLoopHandler(private val protocol: NioProtocol, private val workerThread: NioThread? = null) {
fun handle(nioThread: NioThread, key: SelectionKey) {
val workerThread: NioThread = workerThread ?: nioThread
try {
when {
key.isAcceptable -> {
val serverChannel = key.channel() as ServerSocketChannel
while (true) {
val channel = serverChannel.accept() ?: break
channel.configureBlocking(false)
workerThread.register(channel, 0) {
protocol.handleConnect(it, workerThread)
}
}
}
}
} catch (e: Throwable) {
try {
protocol.exceptionCause(key, nioThread, e)
} catch (e1: Throwable) {
e.printStackTrace()
e1.printStackTrace()
key.cancel()
key.channel().close()
}
}
}
}

View File

@ -0,0 +1,29 @@
package cn.tursom.niothread.loophandler
import cn.tursom.socket.NioProtocol
import cn.tursom.niothread.NioThread
import java.nio.channels.SelectionKey
class WorkerLoopHandler(private val protocol: NioProtocol) {
fun handle(nioThread: NioThread, key: SelectionKey) {
try {
when {
key.isReadable -> {
protocol.handleRead(key, nioThread)
}
key.isWritable -> {
protocol.handleWrite(key, nioThread)
}
}
} catch (e: Throwable) {
try {
protocol.exceptionCause(key, nioThread, e)
} catch (e1: Throwable) {
e.printStackTrace()
e1.printStackTrace()
key.cancel()
key.channel().close()
}
}
}
}

View File

@ -0,0 +1,87 @@
package cn.tursom.socket
import cn.tursom.buffer.MultipleByteBuffer
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.pool.MemoryPool
import cn.tursom.niothread.NioThread
import java.io.Closeable
import java.net.SocketException
import java.nio.channels.SelectionKey
import java.nio.channels.SocketChannel
interface AsyncSocket : Closeable {
val open: Boolean
val channel: SocketChannel
val key: SelectionKey
val nioThread: NioThread
suspend fun write(buffer: Array<out ByteBuffer>, timeout: Long = 0L): Long
suspend fun read(buffer: Array<out ByteBuffer>, timeout: Long = 0L): Long
suspend fun write(buffer: ByteBuffer, timeout: Long = 0L): Int = write(arrayOf(buffer), timeout).toInt()
suspend fun read(buffer: ByteBuffer, timeout: Long = 0L): Int = read(arrayOf(buffer), timeout).toInt()
suspend fun write(buffer: MultipleByteBuffer, timeout: Long = 0L): Long = write(buffer.buffers, timeout)
suspend fun read(buffer: MultipleByteBuffer, timeout: Long = 0L): Long = read(buffer.buffers, timeout)
/**
* 在有数据读取的时候自动由内存池分配内存
*/
@Throws(SocketException::class)
suspend fun read(pool: MemoryPool, timeout: Long = 0L): ByteBuffer
override fun close()
fun waitMode() {
if (Thread.currentThread() == nioThread.thread) {
if (key.isValid) key.interestOps(SelectionKey.OP_WRITE)
} else {
nioThread.execute { if (key.isValid) key.interestOps(0) }
nioThread.wakeup()
}
}
fun readMode() {
if (Thread.currentThread() == nioThread.thread) {
if (key.isValid) key.interestOps(SelectionKey.OP_WRITE)
} else {
nioThread.execute {
if (key.isValid) key.interestOps(SelectionKey.OP_READ)
}
nioThread.wakeup()
}
}
fun writeMode() {
if (Thread.currentThread() == nioThread.thread) {
if (key.isValid) key.interestOps(SelectionKey.OP_WRITE)
} else {
nioThread.execute { if (key.isValid) key.interestOps(SelectionKey.OP_WRITE) }
nioThread.wakeup()
}
}
/**
* 如果通道已断开则会抛出异常
*/
suspend fun recv(buffer: ByteBuffer, timeout: Long = 0): Int {
if (buffer.writeable == 0) return emptyBufferCode
val readSize = read(buffer, timeout)
if (readSize < 0) {
throw SocketException("channel closed")
}
return readSize
}
suspend fun recv(buffers: Array<out ByteBuffer>, timeout: Long = 0): Long {
if (buffers.isEmpty()) return emptyBufferLongCode
val readSize = read(buffers, timeout)
if (readSize < 0) {
throw SocketException("channel closed")
}
return readSize
}
companion object {
const val emptyBufferCode = 0
const val emptyBufferLongCode = 0L
}
}

View File

@ -0,0 +1,9 @@
package cn.tursom.socket
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.pool.MemoryPool
interface BufferedAsyncSocket : AsyncSocket {
val pool: MemoryPool
suspend fun read(timeout: Long = 0L): ByteBuffer = read(pool, timeout)
}

View File

@ -0,0 +1,8 @@
package cn.tursom.socket
import cn.tursom.core.pool.MemoryPool
class BufferedNioSocket(
val socket: AsyncSocket,
override val pool: MemoryPool
) : BufferedAsyncSocket, AsyncSocket by socket

View File

@ -0,0 +1,51 @@
package cn.tursom.socket
import cn.tursom.niothread.WorkerLoopNioThread
import cn.tursom.niothread.loophandler.WorkerLoopHandler
import java.net.InetSocketAddress
import java.net.SocketException
import java.nio.channels.SelectableChannel
import java.nio.channels.SelectionKey
import java.nio.channels.SocketChannel
import java.util.concurrent.TimeoutException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
@Suppress("MemberVisibilityCanBePrivate")
object NioClient {
private const val TIMEOUT = 1000L
private val protocol = NioSocket.nioSocketProtocol
@JvmStatic
private val nioThread = WorkerLoopNioThread(
"nioClient",
daemon = true,
workLoop = WorkerLoopHandler(protocol)::handle
)
suspend fun connect(host: String, port: Int, timeout: Long = 0): NioSocket {
val key: SelectionKey = suspendCoroutine { cont ->
val channel = getConnection(host, port)
val timeoutTask = if (timeout > 0) NioSocket.timer.exec(timeout) {
channel.close()
cont.resumeWithException(TimeoutException())
} else {
null
}
nioThread.register(channel, 0) { key ->
timeoutTask?.cancel()
cont.resume(key)
}
}
return NioSocket(key, nioThread)
}
private fun getConnection(host: String, port: Int): SelectableChannel {
val channel = SocketChannel.open()!!
if (!channel.connect(InetSocketAddress(host, port))) {
throw SocketException("connection failed")
}
channel.configureBlocking(false)
return channel
}
}

View File

@ -0,0 +1,23 @@
package cn.tursom.socket
import cn.tursom.niothread.NioThread
import java.nio.channels.SelectionKey
interface NioProtocol {
@Throws(Throwable::class)
fun handleConnect(key: SelectionKey, nioThread: NioThread) {
}
@Throws(Throwable::class)
fun handleRead(key: SelectionKey, nioThread: NioThread)
@Throws(Throwable::class)
fun handleWrite(key: SelectionKey, nioThread: NioThread)
@Throws(Throwable::class)
fun exceptionCause(key: SelectionKey, nioThread: NioThread, e: Throwable) {
key.cancel()
key.channel().close()
e.printStackTrace()
}
}

View File

@ -0,0 +1,163 @@
package cn.tursom.socket
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.read
import cn.tursom.core.buffer.write
import cn.tursom.core.pool.MemoryPool
import cn.tursom.core.timer.Timer
import cn.tursom.core.timer.TimerTask
import cn.tursom.core.timer.WheelTimer
import cn.tursom.niothread.NioThread
import java.net.SocketException
import java.nio.channels.SelectionKey
import java.nio.channels.SocketChannel
import java.util.concurrent.TimeoutException
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
/**
* 异步协程套接字对象
*/
class NioSocket(override val key: SelectionKey, override val nioThread: NioThread) : AsyncSocket {
override val channel: SocketChannel = key.channel() as SocketChannel
override val open: Boolean get() = channel.isOpen && key.isValid
override suspend fun read(buffer: ByteBuffer, timeout: Long): Int {
if (buffer.writeable == 0) return emptyBufferCode
return operate {
waitRead(timeout)
channel.read(buffer)
}
}
override suspend fun read(buffer: Array<out ByteBuffer>, timeout: Long): Long {
if (buffer.isEmpty() && buffer.all { it.writeable != 0 }) return emptyBufferLongCode
return operate {
waitRead(timeout)
channel.read(buffer)
}
}
override suspend fun write(buffer: ByteBuffer, timeout: Long): Int {
if (buffer.readable == 0) return emptyBufferCode
return operate {
waitWrite(timeout)
channel.write(buffer)
}
}
override suspend fun write(buffer: Array<out ByteBuffer>, timeout: Long): Long {
if (buffer.isEmpty() && buffer.all { it.readable != 0 }) return emptyBufferLongCode
return operate {
waitWrite(timeout)
channel.write(buffer)
}
}
override suspend fun read(pool: MemoryPool, timeout: Long): ByteBuffer = operate {
waitRead(timeout)
val buffer = pool.get()
if (channel.read(buffer) < 0) throw SocketException()
buffer
}
override fun close() {
if (channel.isOpen || key.isValid) {
nioThread.execute {
channel.close()
key.cancel()
}
nioThread.wakeup()
}
}
private inline fun <T> operate(action: () -> T): T {
return try {
action()
} catch (e: Exception) {
waitMode()
throw e
}
}
private suspend inline fun waitRead(timeout: Long = 0) {
suspendCoroutine<Int> {
key.attach(Context(it, if (timeout > 0) timer.exec(timeout) {
key.attach(null)
waitMode()
it.resumeWithException(TimeoutException())
} else null))
readMode()
nioThread.wakeup()
}
}
private suspend inline fun waitWrite(timeout: Long = 0) {
suspendCoroutine<Int> {
key.attach(Context(it, if (timeout > 0) timer.exec(timeout) {
key.attach(null)
waitMode()
it.resumeWithException(TimeoutException())
} else null))
writeMode()
nioThread.wakeup()
}
}
data class Context(val cont: Continuation<Int>, val timeoutTask: TimerTask? = null)
data class ConnectContext(val cont: Continuation<SelectionKey>, val timeoutTask: TimerTask? = null)
protected fun finalize() {
close()
}
/**
* 伴生对象
*/
companion object {
val nioSocketProtocol = object : NioProtocol {
override fun handleConnect(key: SelectionKey, nioThread: NioThread) {
key.interestOps(0)
val context = key.attachment() as ConnectContext? ?: return
context.timeoutTask?.cancel()
context.cont.resume(key)
}
override fun handleRead(key: SelectionKey, nioThread: NioThread) {
key.interestOps(0)
//logE("read ready")
val context = key.attachment() as Context? ?: return
context.timeoutTask?.cancel()
context.cont.resume(0)
}
override fun handleWrite(key: SelectionKey, nioThread: NioThread) {
key.interestOps(0)
val context = key.attachment() as Context? ?: return
context.timeoutTask?.cancel()
context.cont.resume(0)
}
override fun exceptionCause(key: SelectionKey, nioThread: NioThread, e: Throwable) {
key.interestOps(0)
val context = key.attachment() as Context?
if (context != null)
context.cont.resumeWithException(e)
else {
key.cancel()
key.channel().close()
e.printStackTrace()
}
}
}
//val timer = StaticWheelTimer.timer
val timer: Timer = WheelTimer.timer
const val emptyBufferCode = 0
const val emptyBufferLongCode = 0L
}
}

View File

@ -0,0 +1,46 @@
package cn.tursom.socket.server
import cn.tursom.core.pool.DirectMemoryPool
import cn.tursom.core.pool.ExpandableMemoryPool
import cn.tursom.core.pool.MarkedMemoryPool
import cn.tursom.core.pool.MemoryPool
import cn.tursom.socket.BufferedAsyncSocket
import cn.tursom.socket.BufferedNioSocket
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
/**
* 带内存池的 NIO 套接字服务器
* 在处理结束后会自动释放由内存池分配的内存
*/
class BuffedNioServer(
port: Int,
private val memoryPool: MemoryPool,
backlog: Int = 50,
coroutineScope: CoroutineScope = GlobalScope,
handler: suspend BufferedAsyncSocket.() -> Unit
) : NioServer(port, backlog, coroutineScope, {
MarkedMemoryPool(memoryPool).use { marked ->
BufferedNioSocket(this, marked).handler()
}
}) {
constructor(
port: Int,
blockSize: Int = 1024,
blockCount: Int = 128,
backlog: Int = 50,
coroutineScope: CoroutineScope = GlobalScope,
handler: suspend BufferedAsyncSocket.() -> Unit
) : this(
port,
ExpandableMemoryPool { DirectMemoryPool(blockSize, blockCount) },
backlog,
coroutineScope,
handler
)
override fun close() {
super.close()
memoryPool.gc()
}
}

View File

@ -0,0 +1,58 @@
package cn.tursom.socket.server
import cn.tursom.niothread.WorkerLoopNioThread
import cn.tursom.niothread.loophandler.BossLoopHandler
import cn.tursom.socket.NioProtocol
import cn.tursom.niothread.loophandler.WorkerLoopHandler
import cn.tursom.niothread.NioThread
import java.net.InetSocketAddress
import java.nio.channels.SelectionKey
import java.nio.channels.ServerSocketChannel
import java.util.concurrent.atomic.AtomicBoolean
/**
* 工作在单线程上的 Nio 服务器
*/
class NioLoopServer(
override val port: Int,
private val protocol: NioProtocol,
private val backLog: Int = 50,
nioThreadFactory: (
threadName: String,
workLoop: (thread: NioThread, key: SelectionKey) -> Unit
) -> NioThread = { name, workLoop ->
WorkerLoopNioThread(name, workLoop = workLoop, daemon = false)
}
) : SocketServer {
private val listenChannel = ServerSocketChannel.open()
private val workerNioThread = nioThreadFactory("nio-worker", WorkerLoopHandler(
protocol
)::handle)
private val bossNioThread = nioThreadFactory("nio-boss", BossLoopHandler(
protocol,
workerNioThread
)::handle)
private val started = AtomicBoolean(false)
override fun run() {
if (started.compareAndSet(false, true)) {
listenChannel.socket().bind(InetSocketAddress(port), backLog)
listenChannel.configureBlocking(false)
bossNioThread.register(listenChannel, SelectionKey.OP_ACCEPT) {}
}
}
override fun close() {
listenChannel.close()
workerNioThread.close()
bossNioThread.close()
}
protected fun finalize() {
close()
}
companion object {
private const val TIMEOUT = 1000L
}
}

View File

@ -0,0 +1,38 @@
package cn.tursom.socket.server
import cn.tursom.socket.AsyncSocket
import cn.tursom.socket.NioSocket
import cn.tursom.socket.NioProtocol
import cn.tursom.niothread.NioThread
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.nio.channels.SelectionKey
/**
* 只有一个管理线程的协程套接字服务器
* 协程运行的线程是独立于管理线程的
*/
open class NioServer(
override val port: Int,
backlog: Int = 50,
coroutineScope: CoroutineScope = GlobalScope,
val handler: suspend AsyncSocket.() -> Unit
) : SocketServer by NioLoopServer(port, object : NioProtocol by NioSocket.nioSocketProtocol {
override fun handleConnect(key: SelectionKey, nioThread: NioThread) {
coroutineScope.launch {
val socket = NioSocket(key, nioThread)
try {
socket.handler()
} catch (e: Exception) {
Exception(e).printStackTrace()
} finally {
try {
socket.close()
} catch (e: Exception) {
}
}
}
}
}, backlog)

View File

@ -0,0 +1,14 @@
package cn.tursom.socket.server
import java.io.Closeable
/**
* 套接字服务器的基本形式提供运行关闭的基本操作
* 其应支持最基本的创建形式
* XXXServer(port) {
* // 业务逻辑
* }
*/
interface SocketServer : Runnable, Closeable {
val port: Int
}

View File

@ -1,3 +1,5 @@
rootProject.name = 'TursomServer'
include 'web', 'aop', 'database', 'database:database-async', 'utils', 'utils:xml', 'utils:async-http', 'web:netty-web'
include 'socket', 'socket:socket-async'
include 'AsyncSocket'

View File

@ -1,7 +1,5 @@
package cn.tursom.socket
import cn.tursom.core.log
import cn.tursom.core.logE
import cn.tursom.core.timer.TimerTask
import cn.tursom.core.timer.WheelTimer
import cn.tursom.socket.niothread.INioThread

View File

@ -1,9 +1,7 @@
package cn.tursom.socket
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.bytebuffer.readNioBuffer
import cn.tursom.core.bytebuffer.writeNioBuffer
import cn.tursom.core.logE
import cn.tursom.core.buffer.read
import cn.tursom.core.buffer.write
import java.io.Closeable
import java.nio.ByteBuffer
@ -13,35 +11,30 @@ interface AsyncSocket : Closeable {
suspend fun write(buffer: ByteBuffer, timeout: Long = 0L): Int = write(arrayOf(buffer), timeout).toInt()
suspend fun read(buffer: ByteBuffer, timeout: Long = 0L): Int = read(arrayOf(buffer), timeout).toInt()
override fun close()
suspend fun write(buffer: AdvanceByteBuffer, timeout: Long = 0): Int {
return if (buffer.bufferCount == 1) {
buffer.readNioBuffer {
//logE(it.toString())
write(it, timeout)
}
} else {
val readMode = buffer.readMode
buffer.readMode()
val value = write(buffer.nioBuffers, timeout).toInt()
if (!readMode) buffer.resumeWriteMode()
value
suspend fun write(buffer: cn.tursom.core.buffer.ByteBuffer, timeout: Long = 0): Int {
return buffer.read {
write(it, timeout)
}
}
suspend fun read(buffer: AdvanceByteBuffer, timeout: Long = 0): Int {
//logE("buffer.bufferCount: ${buffer.bufferCount}")
//logE("AsyncSocket.read(buffer: AdvanceByteBuffer, timeout: Long = 0): buffer: $buffer")
return if (buffer.bufferCount == 1) {
buffer.writeNioBuffer {
read(it, timeout)
}
} else {
val readMode = buffer.readMode
buffer.resumeWriteMode()
val value = read(buffer.nioBuffers, timeout).toInt()
if (readMode) buffer.readMode()
value
suspend fun read(buffer: cn.tursom.core.buffer.ByteBuffer, timeout: Long = 0): Int {
return buffer.write {
read(it, timeout)
}
}
suspend fun write(buffers: Array<out cn.tursom.core.buffer.ByteBuffer>, timeout: Long): Long {
val nioBuffer = buffers.map { it.readBuffer() }.toTypedArray()
val writeSize = write(nioBuffer, timeout)
buffers.forEachIndexed { index, byteBuffer -> byteBuffer.finishRead(nioBuffer[index]) }
return writeSize
}
suspend fun write(buffers: Collection<cn.tursom.core.buffer.ByteBuffer>, timeout: Long): Long {
val nioBuffer = buffers.map { it.readBuffer() }.toTypedArray()
val writeSize = write(nioBuffer, timeout)
buffers.forEachIndexed { index, byteBuffer -> byteBuffer.finishRead(nioBuffer[index]) }
return writeSize
}
}

View File

@ -1,9 +1,7 @@
package cn.tursom.socket
import cn.tursom.core.buffer.write
import cn.tursom.socket.niothread.INioThread
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.bytebuffer.writeNioBuffer
import cn.tursom.core.logE
import java.net.SocketException
import java.nio.ByteBuffer
import java.nio.channels.SelectionKey
@ -13,7 +11,7 @@ interface IAsyncNioSocket : AsyncSocket {
val channel: SocketChannel
val key: SelectionKey
val nioThread: INioThread
fun waitMode() {
if (Thread.currentThread() == nioThread.thread) {
if (key.isValid) key.interestOps(SelectionKey.OP_WRITE)
@ -22,7 +20,7 @@ interface IAsyncNioSocket : AsyncSocket {
nioThread.wakeup()
}
}
fun readMode() {
//logE("readMode()")
if (Thread.currentThread() == nioThread.thread) {
@ -36,7 +34,7 @@ interface IAsyncNioSocket : AsyncSocket {
nioThread.wakeup()
}
}
fun writeMode() {
if (Thread.currentThread() == nioThread.thread) {
if (key.isValid) key.interestOps(SelectionKey.OP_WRITE)
@ -45,7 +43,7 @@ interface IAsyncNioSocket : AsyncSocket {
nioThread.wakeup()
}
}
suspend fun read(buffer: ByteBuffer): Int = read(arrayOf(buffer)).toInt()
suspend fun write(buffer: ByteBuffer): Int = write(arrayOf(buffer)).toInt()
suspend fun read(buffer: Array<out ByteBuffer>): Long
@ -61,7 +59,7 @@ interface IAsyncNioSocket : AsyncSocket {
}
return readSize
}
suspend fun recv(buffer: ByteBuffer, timeout: Long): Int {
if (buffer.remaining() == 0) return emptyBufferCode
val readSize = read(buffer, timeout)
@ -70,7 +68,7 @@ interface IAsyncNioSocket : AsyncSocket {
}
return readSize
}
suspend fun recv(buffers: Array<out ByteBuffer>, timeout: Long): Long {
if (buffers.isEmpty()) return emptyBufferLongCode
val readSize = read(buffers, timeout)
@ -79,21 +77,13 @@ interface IAsyncNioSocket : AsyncSocket {
}
return readSize
}
suspend fun recv(buffer: AdvanceByteBuffer, timeout: Long = 0): Int {
return if (buffer.bufferCount == 1) {
buffer.writeNioBuffer {
recv(it, timeout)
}
} else {
val readMode = buffer.readMode
buffer.resumeWriteMode()
val value = recv(buffer.nioBuffers, timeout).toInt()
if (readMode) buffer.readMode()
value
suspend fun recv(buffer: cn.tursom.core.buffer.ByteBuffer, timeout: Long = 0): Int {
return buffer.write {
recv(it, timeout)
}
}
companion object {
const val emptyBufferCode = 0
const val emptyBufferLongCode = 0L

View File

@ -1,10 +1,10 @@
package cn.tursom.socket.enhance
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.buffer.ByteBuffer
import java.io.Closeable
interface SocketReader<T> : Closeable {
suspend fun get(buffer: AdvanceByteBuffer, timeout: Long = 0): T
override fun close()
suspend fun get(buffer: ByteBuffer, timeout: Long = 0): T
override fun close()
}

View File

@ -3,5 +3,11 @@ package cn.tursom.socket.enhance
import java.io.Closeable
interface SocketWriter<T> : Closeable {
suspend fun put(value: T, timeout: Long = 0)
suspend fun put(value: T, timeout: Long) {
put(value)
flush(timeout)
}
suspend fun put(value: T)
suspend fun flush(timeout: Long = 0)
}

View File

@ -1,37 +1,37 @@
package cn.tursom.socket.enhance.impl
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.HeapByteBuffer
import cn.tursom.socket.IAsyncNioSocket
import cn.tursom.socket.enhance.SocketReader
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.bytebuffer.ByteArrayAdvanceByteBuffer
class LengthFieldBasedFrameReader(
val prevReader: SocketReader<AdvanceByteBuffer>
) : SocketReader<AdvanceByteBuffer> {
val prevReader: SocketReader<ByteBuffer>
) : SocketReader<ByteBuffer> {
constructor(socket: IAsyncNioSocket) : this(SimpSocketReader(socket))
override suspend fun get(buffer: AdvanceByteBuffer, timeout: Long): AdvanceByteBuffer {
override suspend fun get(buffer: ByteBuffer, timeout: Long): ByteBuffer {
val rBuf = prevReader.get(buffer, timeout)
val blockSize = rBuf.getInt()
if (rBuf.readableSize == blockSize) {
if (rBuf.readable == blockSize) {
return rBuf
} else if (rBuf.readableSize > blockSize) {
} else if (rBuf.readable > blockSize) {
return if (rBuf.hasArray) {
val retBuf = ByteArrayAdvanceByteBuffer(rBuf.array, rBuf.readOffset, blockSize)
val retBuf = HeapByteBuffer(rBuf.array, rBuf.readOffset, blockSize)
rBuf.readPosition += blockSize
retBuf
} else {
val targetBuffer = ByteArrayAdvanceByteBuffer(blockSize)
val targetBuffer = HeapByteBuffer(blockSize)
rBuf.writeTo(targetBuffer)
targetBuffer
}
}
val targetBuffer = ByteArrayAdvanceByteBuffer(blockSize)
val targetBuffer = HeapByteBuffer(blockSize)
rBuf.writeTo(targetBuffer)
while (targetBuffer.writeableSize != 0) {
while (targetBuffer.writeable != 0) {
val rBuf2 = prevReader.get(buffer, timeout)
if (rBuf2.readableSize == 0) return targetBuffer
if (rBuf2.readable == 0) return targetBuffer
rBuf2.writeTo(targetBuffer)
}
return targetBuffer

View File

@ -1,33 +1,38 @@
package cn.tursom.socket.enhance.impl
import cn.tursom.buffer.MultipleByteBuffer
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.ArrayByteBuffer
import cn.tursom.socket.IAsyncNioSocket
import cn.tursom.socket.enhance.SocketWriter
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.bytebuffer.ByteArrayAdvanceByteBuffer
import cn.tursom.core.bytebuffer.MultiAdvanceByteBuffer
import cn.tursom.core.pool.DirectMemoryPool
import cn.tursom.core.pool.ExpandableMemoryPool
class LengthFieldPrependWriter(
val prevWriter: SocketWriter<AdvanceByteBuffer>
) : SocketWriter<AdvanceByteBuffer> {
constructor(socket: IAsyncNioSocket) : this(SimpSocketWriter(socket))
val prevWriter: SocketWriter<ByteBuffer>
) : SocketWriter<ByteBuffer> {
constructor(socket: IAsyncNioSocket) : this(SimpSocketWriter(socket))
override suspend fun put(value: AdvanceByteBuffer, timeout: Long) {
val memToken = directMemoryPool.allocate()
val buffer = directMemoryPool.getAdvanceByteBuffer(memToken) ?: ByteArrayAdvanceByteBuffer(4)
buffer.put(value.readableSize)
prevWriter.put(MultiAdvanceByteBuffer(buffer, value))
directMemoryPool.free(memToken)
}
override suspend fun put(value: ByteBuffer) {
val buffer = directMemoryPool.getMemory()
buffer.put(value.readable)
prevWriter.put(buffer)
prevWriter.put(value)
buffer.close()
}
override fun close() {
prevWriter.close()
}
override suspend fun flush(timeout: Long) {
prevWriter.flush()
}
companion object {
@JvmStatic
private val directMemoryPool = DirectMemoryPool(4, 1024)
}
override fun close() {
prevWriter.close()
}
companion object {
@JvmStatic
private val directMemoryPool = ExpandableMemoryPool { DirectMemoryPool(4, 64) }
}
}

View File

@ -1,13 +1,13 @@
package cn.tursom.socket.enhance.impl
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.socket.IAsyncNioSocket
import cn.tursom.socket.enhance.SocketReader
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
class SimpSocketReader(
val socket: IAsyncNioSocket
) : SocketReader<AdvanceByteBuffer> {
override suspend fun get(buffer: AdvanceByteBuffer, timeout: Long): AdvanceByteBuffer {
) : SocketReader<ByteBuffer> {
override suspend fun get(buffer: ByteBuffer, timeout: Long): ByteBuffer {
buffer.reset()
if (socket.read(buffer) < 0) {
socket.close()

View File

@ -1,17 +1,26 @@
package cn.tursom.socket.enhance.impl
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.socket.IAsyncNioSocket
import cn.tursom.socket.enhance.SocketWriter
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import java.util.concurrent.ConcurrentLinkedQueue
class SimpSocketWriter(
val socket: IAsyncNioSocket
) : SocketWriter<AdvanceByteBuffer> {
override suspend fun put(value: AdvanceByteBuffer, timeout: Long) {
socket.write(value, timeout)
}
val socket: IAsyncNioSocket
) : SocketWriter<ByteBuffer> {
private val bufferQueue = ConcurrentLinkedQueue<ByteBuffer>()
override suspend fun put(value: ByteBuffer) {
bufferQueue.offer(value)
}
override fun close() {
socket.close()
}
override suspend fun flush(timeout: Long) {
val buffers = bufferQueue.toTypedArray()
bufferQueue.clear()
socket.write(buffers, timeout)
buffers.forEach { it.close() }
}
override fun close() {
socket.close()
}
}

View File

@ -1,15 +1,15 @@
package cn.tursom.socket.enhance.impl
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.socket.IAsyncNioSocket
import cn.tursom.socket.enhance.SocketReader
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
class StringReader(
val prevReader: SocketReader<AdvanceByteBuffer>
val prevReader: SocketReader<ByteBuffer>
) : SocketReader<String> {
constructor(socket: IAsyncNioSocket) : this(LengthFieldBasedFrameReader(socket))
override suspend fun get(buffer: AdvanceByteBuffer, timeout: Long): String {
override suspend fun get(buffer: ByteBuffer, timeout: Long): String {
return prevReader.get(buffer, timeout).getString()
}

View File

@ -1,17 +1,17 @@
package cn.tursom.socket.enhance.impl
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.socket.IAsyncNioSocket
import cn.tursom.socket.enhance.EnhanceSocket
import cn.tursom.socket.enhance.SocketReader
import cn.tursom.socket.enhance.SocketWriter
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
class StringSocket(
socket: IAsyncNioSocket,
prevReader: SocketReader<AdvanceByteBuffer> = LengthFieldBasedFrameReader(socket),
prevWriter: SocketWriter<AdvanceByteBuffer> = LengthFieldPrependWriter(socket)
socket: IAsyncNioSocket,
prevReader: SocketReader<ByteBuffer> = LengthFieldBasedFrameReader(socket),
prevWriter: SocketWriter<ByteBuffer> = LengthFieldPrependWriter(socket)
) : EnhanceSocket<String, String> by UnionEnhanceSocket(
socket,
StringReader(prevReader),
StringWriter(prevWriter)
socket,
StringReader(prevReader),
StringWriter(prevWriter)
)

View File

@ -1,22 +1,26 @@
package cn.tursom.socket.enhance.impl
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.HeapByteBuffer
import cn.tursom.socket.IAsyncNioSocket
import cn.tursom.socket.enhance.SocketWriter
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.bytebuffer.ByteArrayAdvanceByteBuffer
class StringWriter(
val prevWriter: SocketWriter<AdvanceByteBuffer>
val prevWriter: SocketWriter<ByteBuffer>
) : SocketWriter<String> {
constructor(socket: IAsyncNioSocket) : this(LengthFieldPrependWriter(socket))
constructor(socket: IAsyncNioSocket) : this(LengthFieldPrependWriter(socket))
override suspend fun put(value: String, timeout: Long) {
val buf = ByteArrayAdvanceByteBuffer(value.toByteArray())
buf.writePosition = buf.limit
prevWriter.put(buf, timeout)
}
override suspend fun put(value: String) {
val buf = HeapByteBuffer(value.toByteArray())
buf.writePosition = buf.capacity
prevWriter.put(buf)
}
override fun close() {
prevWriter.close()
}
override suspend fun flush(timeout: Long) {
prevWriter.flush(timeout)
}
override fun close() {
prevWriter.close()
}
}

View File

@ -1,13 +1,13 @@
package cn.tursom.socket.enhance.impl
import cn.tursom.socket.enhance.SocketReader
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.timer.TimerTask
import cn.tursom.core.timer.WheelTimer
import cn.tursom.socket.enhance.SocketReader
class TimeoutReader<Read>(val prevReader: SocketReader<Read>, val timeout: Long = 5000L) : SocketReader<Read> {
private var timerTask: TimerTask? = null
override suspend fun get(buffer: AdvanceByteBuffer, timeout: Long): Read {
override suspend fun get(buffer: ByteBuffer, timeout: Long): Read {
timerTask?.cancel()
timerTask = timer.exec(this.timeout) {
prevReader.close()

View File

@ -1,25 +1,23 @@
package cn.tursom.socket.server
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.bytebuffer.ByteArrayAdvanceByteBuffer
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.pool.DirectMemoryPool
import cn.tursom.core.pool.MemoryPool
import cn.tursom.core.pool.usingAdvanceByteBuffer
import cn.tursom.socket.AsyncNioSocket
/**
* 带内存池的 NIO 套接字服务器<br />
* 其构造函数是标准写法的改造会向 handler 方法传入一个 AdvanceByteBuffer默认是 DirectAdvanceByteBuffer
* 当内存池用完之后会换为 ByteArrayAdvanceByteBuffer
* 其构造函数是标准写法的改造会向 handler 方法传入一个 ByteBuffer默认是 DirectByteBuffer
* 当内存池用完之后会换为 ByteArrayByteBuffer
*/
class BuffedAsyncNioServer(
port: Int,
memoryPool: MemoryPool,
backlog: Int = 50,
handler: suspend AsyncNioSocket.(buffer: AdvanceByteBuffer) -> Unit
handler: suspend AsyncNioSocket.(buffer: ByteBuffer) -> Unit
) : IAsyncNioServer by AsyncNioServer(port, backlog, {
memoryPool.usingAdvanceByteBuffer {
handler(it ?: ByteArrayAdvanceByteBuffer(memoryPool.blockSize))
memoryPool {
handler(it)
}
}) {
constructor(
@ -27,6 +25,6 @@ class BuffedAsyncNioServer(
blockSize: Int = 1024,
blockCount: Int = 128,
backlog: Int = 50,
handler: suspend AsyncNioSocket.(buffer: AdvanceByteBuffer) -> Unit
handler: suspend AsyncNioSocket.(buffer: ByteBuffer) -> Unit
) : this(port, DirectMemoryPool(blockSize, blockCount), backlog, handler)
}

View File

@ -1,30 +0,0 @@
import cn.tursom.core.bytebuffer.ByteArrayAdvanceByteBuffer
import cn.tursom.core.pool.DirectMemoryPool
import cn.tursom.core.pool.usingAdvanceByteBuffer
import cn.tursom.socket.server.AsyncNioServer
fun main() {
// 服务器端口,可任意指定
val port = 12345
// 创建一个直接内存池每个块是1024字节共有256个快
val memoryPool = DirectMemoryPool(1024, 256)
// 创建服务器对象
val server = AsyncNioServer(port) {
// 这里处理业务逻辑,套接字对象被以 this 的方式传进来
// 从内存池中获取一个内存块
memoryPool.usingAdvanceByteBuffer {
// 检查是否获取成功,不成功就创建一个堆缓冲
val buffer = it ?: ByteArrayAdvanceByteBuffer(1024)
// 从套接字中读数据,五秒之内没有数据就抛出异常
read(buffer, 5000)
// 输出读取到的数据
println("${System.currentTimeMillis()}: recv from ${channel.remoteAddress}: ${buffer.toString(buffer.readableSize)}")
// 原封不动的返回数据
write(buffer)
// 代码块结束后,框架会自动释放连接
}
}
// 创建一个新线程去启动服务器
Thread(server, "echoServerStarter").start()
}

View File

@ -1,93 +0,0 @@
import cn.tursom.core.bytebuffer.ByteArrayAdvanceByteBuffer
import cn.tursom.core.log
import cn.tursom.core.pool.DirectMemoryPool
import cn.tursom.core.pool.usingAdvanceByteBuffer
import cn.tursom.socket.AsyncNioClient
import cn.tursom.socket.server.AsyncNioServer
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.lang.Thread.sleep
import java.net.SocketException
import java.util.concurrent.TimeoutException
import java.util.concurrent.atomic.AtomicInteger
fun main() {
// 服务器端口,可任意指定
val port = 12345
// 创建一个直接内存池每个块是1024字节共有256个快
val memoryPool = DirectMemoryPool(1024, 256)
// 创建服务器对象
val server = AsyncNioServer(port) {
// 这里处理业务逻辑,套接字对象被以 this 的方式传进来
// 从内存池中获取一个内存块
memoryPool.usingAdvanceByteBuffer {
// 检查是否获取成功,不成功就创建一个堆缓冲
val buffer = it ?: ByteArrayAdvanceByteBuffer(1024)
try {
while (true) {
buffer.clear()
// 从套接字中读数据,五秒之内没有数据就抛出异常
if (read(buffer, 10_000) < 0) {
return@AsyncNioServer
}
// 输出读取到的数据
//log("server recv from ${channel.remoteAddress}: [${buffer.readableSize}] ${buffer.toString(buffer.readableSize)}")
// 原封不动的返回数据
val writeSize = write(buffer)
//log("server send [$writeSize] bytes")
}
} catch (e: TimeoutException) {
}
// 代码块结束后,框架会自动释放连接
}
}
server.run()
val connectionCount = 300
val dataPerConn = 10
val testData = "testData".toByteArray()
val remain = AtomicInteger(connectionCount)
val clientMemoryPool = DirectMemoryPool(1024, connectionCount)
val start = System.currentTimeMillis()
repeat(connectionCount) {
GlobalScope.launch {
val socket = AsyncNioClient.connect("127.0.0.1", port)
clientMemoryPool.usingAdvanceByteBuffer {
// 检查是否获取成功,不成功就创建一个堆缓冲
val buffer = it ?: ByteArrayAdvanceByteBuffer(1024)
try {
repeat(dataPerConn) {
buffer.clear()
buffer.put(testData)
//log("client sending: [${buffer.readableSize}] ${buffer.toString(buffer.readableSize)}")
val writeSize = socket.write(buffer)
//log("client write [$writeSize] bytes")
//log(buffer.toString())
val readSize = socket.read(buffer)
//log(buffer.toString())
//log("client recv: [$readSize:${buffer.readableSize}] ${buffer.toString(buffer.readableSize)}")
}
} catch (e: Exception) {
Exception(e).printStackTrace()
} finally {
socket.close()
}
}
remain.decrementAndGet()
}
}
while (remain.get() != 0) {
println(remain.get())
sleep(500)
}
val end = System.currentTimeMillis()
println(end - start)
server.close()
}

View File

@ -1,59 +0,0 @@
package cn.tursom.socket.server
import cn.tursom.core.bytebuffer.ByteArrayAdvanceByteBuffer
import cn.tursom.core.log
import cn.tursom.core.logE
import cn.tursom.socket.AsyncAioClient
import cn.tursom.socket.SocketClient
import kotlinx.coroutines.runBlocking
import org.junit.Test
class AsyncNioServerTest {
private val testMsg = "hello"
private val port = 12345
private val server = AsyncNioServer(port) {
log("new connection")
val buffer = ByteArrayAdvanceByteBuffer(1024)
while (true) {
buffer.clear()
read(buffer, 5000)
logE("server recv: ${buffer.toString(buffer.readableSize)}")
write(buffer, 5000)
}
}
init {
server.run()
}
//@Test
fun testAsyncNioServer() {
runBlocking {
val client = AsyncAioClient.connect("127.0.0.1", port)
log("connect to server")
val buffer = ByteArrayAdvanceByteBuffer(1024)
repeat(10) {
buffer.clear()
buffer.put(testMsg)
client.write(buffer, 5000)
buffer.clear()
client.read(buffer, 5000)
log("server recv: ${buffer.getString()}")
}
}
}
//@Test
fun testAsyncNioServerSocket() {
SocketClient("localhost", port) {
val buffer = ByteArray(1024)
repeat(10) {
send(testMsg)
val readSize = inputStream.read(buffer)
val recv = String(buffer, 0, readSize)
log(recv)
}
}
}
}

View File

@ -1,10 +1,8 @@
package cn.tursom.socket.niothread
import cn.tursom.core.timer.WheelTimer
import java.nio.channels.Selector
import java.util.concurrent.Callable
import java.util.concurrent.LinkedBlockingDeque
import java.util.concurrent.atomic.AtomicBoolean
@Suppress("MemberVisibilityCanBePrivate", "CanBeParameter")
class WorkerLoopNioThread(

View File

@ -1,66 +0,0 @@
package cn.tursom.socket.server
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.bytebuffer.ByteArrayAdvanceByteBuffer
import cn.tursom.core.bytebuffer.readNioBuffer
import cn.tursom.core.bytebuffer.writeNioBuffer
import cn.tursom.core.pool.DirectMemoryPool
import cn.tursom.core.pool.MemoryPool
import cn.tursom.socket.INioProtocol
import cn.tursom.socket.SocketClient
import cn.tursom.socket.niothread.INioThread
import org.junit.Test
import java.nio.channels.SelectionKey
import java.nio.channels.SocketChannel
class NioServerTest {
private val port = 12345
@Test
fun testNioServer() {
val memoryPool: MemoryPool = DirectMemoryPool(1024, 256)
val server = NioServer(port, object : INioProtocol {
override fun handleConnect(key: SelectionKey, nioThread: INioThread) {
val memoryToken = memoryPool.allocate()
key.attach(memoryToken to (memoryPool.getAdvanceByteBuffer(memoryToken) ?: ByteArrayAdvanceByteBuffer(1024)))
key.interestOps(SelectionKey.OP_READ)
}
override fun handleRead(key: SelectionKey, nioThread: INioThread) {
val channel = key.channel() as SocketChannel
val buffer = (key.attachment() as Pair<Int, AdvanceByteBuffer>).second
buffer.writeNioBuffer {
channel.read(it)
}
println("record from client: ${buffer.toString(buffer.readableSize)}")
key.interestOps(SelectionKey.OP_WRITE)
}
override fun handleWrite(key: SelectionKey, nioThread: INioThread) {
val channel = key.channel() as SocketChannel
val buffer = (key.attachment() as Pair<Int, AdvanceByteBuffer>).second
println("send to client: ${buffer.toString(buffer.readableSize)}")
buffer.readNioBuffer {
channel.write(it)
}
buffer.reset()
key.interestOps(SelectionKey.OP_READ)
}
override fun exceptionCause(key: SelectionKey, nioThread: INioThread, e: Throwable) {
super.exceptionCause(key, nioThread, e)
val memoryToken = (key.attachment() as Pair<Int, AdvanceByteBuffer>).first
memoryPool.free(memoryToken)
key.channel().close()
key.cancel()
}
})
server.run()
val socket = SocketClient("127.0.0.1", port)
val buffer = ByteArray(1024)
socket.outputStream.write("Hello".toByteArray())
val readCount = socket.inputStream.read(buffer)
println(buffer.copyOfRange(0, readCount).toString(Charsets.UTF_8))
server.close()
}
}

View File

@ -1,9 +1,8 @@
package cn.tursom.core
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.bytebuffer.readNioBuffer
import cn.tursom.core.bytebuffer.writeNioBuffer
import java.nio.ByteBuffer
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.read
import cn.tursom.core.buffer.write
import java.nio.channels.AsynchronousFileChannel
import java.nio.channels.CompletionHandler
import java.nio.file.Files
@ -18,87 +17,73 @@ import kotlin.coroutines.suspendCoroutine
@Suppress("MemberVisibilityCanBePrivate")
class AsyncFile(val path: Path) {
constructor(path: String) : this(Paths.get(path))
constructor(path: String) : this(Paths.get(path))
private var existsCache = false
private var existsCache = false
val exists: Boolean
get() {
val exists = Files.exists(path)
existsCache = exists
return exists
}
val size get() = if (existsCache || exists) Files.size(path) else 0
val exists: Boolean
get() {
val exists = Files.exists(path)
existsCache = exists
return exists
}
val size get() = if (existsCache || exists) Files.size(path) else 0
val writeChannel: AsynchronousFileChannel by lazy { AsynchronousFileChannel.open(path, StandardOpenOption.WRITE) }
val readChannel: AsynchronousFileChannel by lazy { AsynchronousFileChannel.open(path, StandardOpenOption.READ) }
val writeChannel: AsynchronousFileChannel by lazy { AsynchronousFileChannel.open(path, StandardOpenOption.WRITE) }
val readChannel: AsynchronousFileChannel by lazy { AsynchronousFileChannel.open(path, StandardOpenOption.READ) }
fun write(buffer: ByteBuffer, position: Long = 0) {
create()
writeChannel.write(buffer, position)
}
fun write(buffer: ByteBuffer, position: Long = 0) {
create()
buffer.read { writeChannel.write(it, position) }
}
suspend fun writeAndWait(buffer: ByteBuffer, position: Long = 0): Int {
create()
return suspendCoroutine {
writeChannel.write(buffer, position, it, handler)
}
}
suspend fun writeAndWait(buffer: ByteBuffer, position: Long = 0): Int {
create()
return suspendCoroutine { cont ->
buffer.read { writeChannel.write(it, position, cont, handler) }
}
}
suspend fun write(buffer: AdvanceByteBuffer, position: Long = 0): Int {
return buffer.readNioBuffer { writeAndWait(it, position) }
}
fun append(buffer: ByteBuffer, position: Long = size) {
write(buffer, position)
}
fun append(buffer: ByteBuffer, position: Long = size) {
write(buffer, position)
}
suspend fun appendAndWait(buffer: ByteBuffer, position: Long = size): Int {
return writeAndWait(buffer, position)
}
suspend fun appendAndWait(buffer: ByteBuffer, position: Long = size): Int {
return writeAndWait(buffer, position)
}
suspend fun read(buffer: ByteBuffer, position: Long = 0): Int {
return suspendCoroutine { cont ->
buffer.write { readChannel.read(it, position, cont, handler) }
}
}
suspend fun append(buffer: AdvanceByteBuffer, position: Long = size): Int {
return buffer.readNioBuffer { appendAndWait(it, position) }
}
fun create() = if (existsCache || !exists) {
Files.createFile(path)
existsCache = true
true
} else {
false
}
suspend fun read(buffer: ByteBuffer, position: Long = 0): Int {
return suspendCoroutine {
readChannel.read(buffer, position, it, handler)
}
}
fun delete(): Boolean {
existsCache = false
return Files.deleteIfExists(path)
}
suspend fun read(buffer: AdvanceByteBuffer, position: Long = 0): Int {
return buffer.writeNioBuffer {
read(it, position)
}
}
fun close() {
try {
writeChannel.close()
readChannel.close()
} catch (e: Exception) {
}
}
fun create() = if (existsCache || !exists) {
Files.createFile(path)
existsCache = true
true
} else {
false
}
fun delete(): Boolean {
existsCache = false
return Files.deleteIfExists(path)
}
fun close() {
try {
writeChannel.close()
readChannel.close()
} catch (e: Exception) {
}
}
companion object {
@JvmStatic
val handler = object : CompletionHandler<Int, Continuation<Int>> {
override fun completed(result: Int, attachment: Continuation<Int>) = attachment.resume(result)
override fun failed(exc: Throwable, attachment: Continuation<Int>) = attachment.resumeWithException(exc)
}
}
companion object {
@JvmStatic
val handler = object : CompletionHandler<Int, Continuation<Int>> {
override fun completed(result: Int, attachment: Continuation<Int>) = attachment.resume(result)
override fun failed(exc: Throwable, attachment: Continuation<Int>) = attachment.resumeWithException(exc)
}
}
}

View File

@ -0,0 +1,186 @@
package cn.tursom.core
import java.io.Serializable
import java.lang.reflect.Field
import java.util.concurrent.atomic.AtomicLongArray
class AtomicBitSet(beginSize: Long = 256, val defaultState: Boolean = false) : Serializable {
@Volatile
private var bitSet = AtomicLongArray(needSize(beginSize))
val size
get() = bitSet.length().toLong() shl 6
val usedSize
get() = bitSet.length() * 8
val usedSizeStr: String
get() {
val memory = usedSize
val b = memory % 1024
val kb = (memory / 1024) % 1024
val mb = (memory / 1024 / 1024) % 1024
return "${if (mb != 0) "$mb MB " else ""}${if (kb != 0) "$kb KB " else ""} $b Byte"
}
val trueCount: Long
get() {
var count = 0L
bitSet.array.forEach { count += it.bitCount }
return count
}
init {
val default = if (defaultState) -1L else 0L
for (i in 0 until bitSet.length()) {
bitSet[i] = default
}
}
operator fun get(index: Long): Boolean {
return bitSet[(index shr 6).toInt()] and getArr[index.toInt() and 63] != 0L
}
fun up(index: Long): Boolean {
val arrayIndex = (index shr 6).toInt()
//bitSet[arrayIndex] = bitSet[arrayIndex] or getArr[index.toInt() and 63]
val expect = bitSet[arrayIndex]
return bitSet.compareAndSet(arrayIndex, expect, expect or getArr[index.toInt() and 63])
}
fun down(index: Long): Boolean {
val arrayIndex = (index shr 6).toInt()
//bitSet[arrayIndex] = bitSet[arrayIndex] and setArr[index.toInt() and 63]
val expect = bitSet[arrayIndex]
return bitSet.compareAndSet(arrayIndex, expect, expect and setArr[index.toInt() and 63])
}
fun upAll() {
for (i in 0 until bitSet.length()) {
bitSet[i] = -1
}
}
fun downAll() {
for (i in 0 until bitSet.length()) {
bitSet[i] = 0
}
}
fun resize(newSIze: Long): Boolean = synchronized(this) {
if (newSIze < this.size) return false
val newSet = AtomicLongArray(needSize(newSIze))
bitSet.array.copyInto(newSet.array)
val default = if (defaultState) -1L else 0
for (i in bitSet.length() until newSet.length()) {
newSet[i] = default
}
bitSet = newSet
return true
}
fun firstUp(): Long {
bitSet.forEachIndexed { index, l ->
if (l != 0L) {
for (i in 0 until 8) {
if (l and scanArray[i] != 0L) {
val baseIndex = i * 8
for (j in 0 until 8) {
if (l and getArr[baseIndex + j] != 0L) return index.toLong() * 64 + baseIndex + j
}
}
}
}
}
return -1
}
fun firstDown(): Long {
bitSet.forEachIndexed { index, l ->
if (l != -1L) {
for (i in 0 until 8) {
if (l.inv() and scanArray[i] != 0L) {
val baseIndex = i * 8
for (j in 0 until 8) {
if (l and getArr[baseIndex + j] == 0L) return index.toLong() * 64 + baseIndex + j
}
}
}
}
}
return -1
}
override fun toString() = "MemoryBitArray(max size=$size, true count=$trueCount, used memory=$usedSizeStr)"
companion object {
@JvmStatic
fun needSize(maxIndex: Long) = ((((maxIndex - 1) shr 6) + 1) and 0xffffffff).toInt()
private val getArr = longArrayOf(
1L shl 0, 1L shl 1, 1L shl 2, 1L shl 3,
1L shl 4, 1L shl 5, 1L shl 6, 1L shl 7,
1L shl 8, 1L shl 9, 1L shl 10, 1L shl 11,
1L shl 12, 1L shl 13, 1L shl 14, 1L shl 15,
1L shl 16, 1L shl 17, 1L shl 18, 1L shl 19,
1L shl 20, 1L shl 21, 1L shl 22, 1L shl 23,
1L shl 24, 1L shl 25, 1L shl 26, 1L shl 27,
1L shl 28, 1L shl 29, 1L shl 30, 1L shl 31,
1L shl 32, 1L shl 33, 1L shl 34, 1L shl 35,
1L shl 36, 1L shl 37, 1L shl 38, 1L shl 39,
1L shl 40, 1L shl 41, 1L shl 42, 1L shl 43,
1L shl 44, 1L shl 45, 1L shl 46, 1L shl 47,
1L shl 48, 1L shl 49, 1L shl 50, 1L shl 51,
1L shl 52, 1L shl 53, 1L shl 54, 1L shl 55,
1L shl 56, 1L shl 57, 1L shl 58, 1L shl 59,
1L shl 60, 1L shl 61, 1L shl 62, 1L shl 63
)
private val setArr = LongArray(64) { getArr[it].inv() }
private val bitCountArray = longArrayOf(
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
)
private val scanArray = longArrayOf(
0xffL, 0xffL shl 8, 0xffL shl 16, 0xffL shl 24,
0xffL shl 32, 0xffL shl 40, 0xffL shl 48, 0xffL shl 56
)
private val Long.bitCount
get() = bitCountArray[toInt().and(0xff)] + bitCountArray[shr(8).toInt().and(0xff)] +
bitCountArray[shr(16).toInt().and(0xff)] + bitCountArray[shr(24).toInt().and(0xff)] +
bitCountArray[shr(32).toInt().and(0xff)] + bitCountArray[shr(40).toInt().and(0xff)] +
bitCountArray[shr(48).toInt().and(0xff)] + bitCountArray[shr(56).toInt().and(0xff)]
private val AtomicLongArray.size get() = length()
private val array: Field = AtomicLongArray::class.java.getDeclaredField("array")
private val AtomicLongArray.array get() = Companion.array.get(this) as LongArray
init {
array.isAccessible = true
}
inline fun AtomicLongArray.forEachIndexed(action: (index: Int, Long) -> Unit) {
repeat(length()) {
action(it, get(it))
}
}
}
}

View File

@ -0,0 +1,22 @@
package cn.tursom.core
import java.util.concurrent.TimeUnit
import java.util.concurrent.ScheduledThreadPoolExecutor
object CurrentTimeMillisClock {
@Volatile
private var tick: Long = System.currentTimeMillis()
val now get() = tick
init {
ScheduledThreadPoolExecutor(1) { runnable ->
val thread = Thread(runnable, "current-time-millis")
thread.isDaemon = true
thread
}.scheduleAtFixedRate({ tick = System.currentTimeMillis() }, 1, 1, TimeUnit.MILLISECONDS)
}
//val now get() = System.currentTimeMillis()
}

View File

@ -2,7 +2,7 @@
package cn.tursom.core
import cn.tursom.core.bytebuffer.HeapByteBuffer
import cn.tursom.core.buffer.impl.HeapByteBuffer
import java.io.*
import java.nio.ByteOrder
@ -544,7 +544,7 @@ private val ByteArrayOutputStream_count = ByteArrayOutputStream::class.java.getD
val ByteArrayOutputStream.buf get() = ByteArrayOutputStream_buf.get(this) as ByteArray
val ByteArrayOutputStream.count get() = ByteArrayOutputStream_count.get(this) as Int
fun ByteArray.toByteBuffer() = HeapByteBuffer.wrap(this, 0, size)
fun ByteArray.toByteBuffer() = HeapByteBuffer(this, 0, size)
inline fun <T> Array<T>.forEachIndex(fromIndex: Int, toIndex: Int, action: (T) -> Unit) {
for (i in fromIndex..toIndex) {

View File

@ -0,0 +1,26 @@
package cn.tursom.core
import java.nio.ByteBuffer
/**
* HOOK java.nio.HeapByteBuffer
*/
object HeapByteBufferUtil {
private val field = ByteBuffer::class.java.getDeclaredField("offset")
init {
field.isAccessible = true
}
fun wrap(array: ByteArray, offset: Int = 0, size: Int = array.size - offset): ByteBuffer {
val buffer = ByteBuffer.wrap(array, 0, offset + size)
//return if (offset == 0) buffer else {
// buffer.position(offset)
// buffer.slice()
//}
if (offset > 0) field.set(buffer, offset)
return buffer
}
fun wrap(string: String) = wrap(string.toByteArray())
}

View File

@ -0,0 +1,95 @@
package cn.tursom.core
import java.util.concurrent.atomic.AtomicLong
class LongBitSet {
private val bitSet = AtomicLong(0)
val trueCount: Long get() = bitSet.get().bitCount
fun up(index: Int) = bitSet.compareAndSet(bitSet.get(), bitSet.get() or getArr[index and 63])
fun down(index: Int) = bitSet.compareAndSet(bitSet.get(), bitSet.get() and setArr[index and 63])
fun firstUp(): Int {
val l = bitSet.get()
if (l != 0L) {
for (i in 0 until 8) {
if (l and scanArray[i] != 0L) {
val baseIndex = i * 8
for (j in 0 until 8) {
if (l and getArr[baseIndex + j] != 0L) return baseIndex + j
}
}
}
}
return -1
}
fun firstDown(): Int {
val l = bitSet.get()
if (l != -1L) {
for (i in 0 until 8) {
if (l.inv() and scanArray[i] != 0L) {
val baseIndex = i * 8
for (j in 0 until 8) {
if (l and getArr[baseIndex + j] == 0L) return baseIndex + j
}
}
}
}
return -1
}
companion object {
private val getArr = longArrayOf(
1L shl 0, 1L shl 1, 1L shl 2, 1L shl 3,
1L shl 4, 1L shl 5, 1L shl 6, 1L shl 7,
1L shl 8, 1L shl 9, 1L shl 10, 1L shl 11,
1L shl 12, 1L shl 13, 1L shl 14, 1L shl 15,
1L shl 16, 1L shl 17, 1L shl 18, 1L shl 19,
1L shl 20, 1L shl 21, 1L shl 22, 1L shl 23,
1L shl 24, 1L shl 25, 1L shl 26, 1L shl 27,
1L shl 28, 1L shl 29, 1L shl 30, 1L shl 31,
1L shl 32, 1L shl 33, 1L shl 34, 1L shl 35,
1L shl 36, 1L shl 37, 1L shl 38, 1L shl 39,
1L shl 40, 1L shl 41, 1L shl 42, 1L shl 43,
1L shl 44, 1L shl 45, 1L shl 46, 1L shl 47,
1L shl 48, 1L shl 49, 1L shl 50, 1L shl 51,
1L shl 52, 1L shl 53, 1L shl 54, 1L shl 55,
1L shl 56, 1L shl 57, 1L shl 58, 1L shl 59,
1L shl 60, 1L shl 61, 1L shl 62, 1L shl 63
)
private val setArr = LongArray(64) { getArr[it].inv() }
private val bitCountArray = longArrayOf(
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
)
private val scanArray = longArrayOf(
0xffL, 0xffL shl 8, 0xffL shl 16, 0xffL shl 24,
0xffL shl 32, 0xffL shl 40, 0xffL shl 48, 0xffL shl 56
)
private val Long.bitCount
get() = bitCountArray[toInt().and(0xff)] + bitCountArray[shr(8).toInt().and(0xff)] +
bitCountArray[shr(16).toInt().and(0xff)] + bitCountArray[shr(24).toInt().and(0xff)] +
bitCountArray[shr(32).toInt().and(0xff)] + bitCountArray[shr(40).toInt().and(0xff)] +
bitCountArray[shr(48).toInt().and(0xff)] + bitCountArray[shr(56).toInt().and(0xff)]
}
}

View File

@ -0,0 +1,31 @@
package cn.tursom.core
import java.util.concurrent.atomic.AtomicReference
open class NonLockLinkedList<T> {
private val root = AtomicReference<TaskListNode<T>?>()
infix fun add(element: T) {
val taskNode = TaskListNode(element, root.get())
while (!root.compareAndSet(taskNode.next, taskNode)) {
taskNode.next = root.get()
}
}
infix operator fun invoke(data: T) = add(data)
fun take(): T? {
var node = root.get()
while (!root.compareAndSet(node, node?.next)) {
node = root.get()
}
return node?.data
}
private class TaskListNode<T>(
val data: T,
@Volatile var next: TaskListNode<T>?
)
class NotSupportedException : Exception()
}

View File

@ -0,0 +1,228 @@
package cn.tursom.core.buffer
import cn.tursom.core.forEachIndex
import java.io.Closeable
import java.io.OutputStream
import java.nio.Buffer
import kotlin.math.min
/**
* 针对 java nio 的弱智 ByteBuffer 的简单封装
* 支持读写 buffer 分离
*/
@Suppress("unused")
interface ByteBuffer : Closeable {
/**
* 使用读 bufferByteBuffer 实现类有义务维护指针正常推进
*/
fun <T> readBuffer(block: (java.nio.ByteBuffer) -> T): T {
val buffer = readBuffer()
return try {
block(buffer)
} finally {
finishRead(buffer)
}
}
/**
* 使用写 bufferByteBuffer 实现类有义务维护指针正常推进
*/
fun <T> writeBuffer(block: (java.nio.ByteBuffer) -> T): T {
val buffer = writeBuffer()
return try {
block(buffer)
} finally {
finishWrite(buffer)
}
}
val readable: Int get() = writePosition - readPosition
val writeable: Int get() = capacity - readPosition
val hasArray: Boolean
val array: ByteArray
val capacity: Int
val arrayOffset: Int
var writePosition: Int
var readPosition: Int
val closed: Boolean get() = false
val resized: Boolean
override fun close() {
}
fun readBuffer(): java.nio.ByteBuffer
fun finishRead(buffer: java.nio.ByteBuffer) {
readPosition = buffer.position()
}
fun writeBuffer(): java.nio.ByteBuffer
fun finishWrite(buffer: java.nio.ByteBuffer) {
readPosition = buffer.position()
}
fun reset()
fun slice(offset: Int, size: Int): ByteBuffer
/**
* @return 底层 nio buffer 是否已更新
*/
fun resize(newSize: Int): Boolean
val writeOffset: Int get() = arrayOffset + writePosition
val readOffset: Int get() = arrayOffset + readPosition
fun clear() {
readPosition = 0
writePosition = 0
}
fun get(): Byte = read { it.get() }
fun getChar(): Char = read { it.char }
fun getShort(): Short = read { it.short }
fun getInt(): Int = read { it.int }
fun getLong(): Long = read { it.long }
fun getFloat(): Float = read { it.float }
fun getDouble(): Double = read { it.double }
fun getBytes(size: Int = readable): ByteArray = read {
val bytes = ByteArray(size)
it.get(bytes)
bytes
}
fun getString(size: Int = readable): String = String(getBytes(size))
fun toString(size: Int): String {
val bytes = getBytes(size)
readPosition -= bytes.size
return String(bytes)
}
fun writeTo(buffer: ByteArray, bufferOffset: Int = 0, size: Int = min(readable, buffer.size)): Int {
val readSize = min(readable, size)
if (hasArray) {
array.copyInto(buffer, bufferOffset, readOffset, readOffset + readSize)
readPosition += readOffset
reset()
} else {
read {
it.put(buffer, bufferOffset, readSize)
}
}
return readSize
}
fun writeTo(os: OutputStream): Int {
val size = readable
if (hasArray) {
os.write(array, readOffset, size)
readPosition += size
reset()
} else {
val buffer = ByteArray(1024)
read {
while (it.remaining() > 0) {
it.put(buffer)
os.write(buffer)
}
}
}
return size
}
fun writeTo(buffer: ByteBuffer): Int {
val size = min(readable, buffer.readable)
if (hasArray) {
buffer.put(array, readOffset, size)
readPosition += size
reset()
} else {
read { read ->
buffer.write { write -> write.put(read) }
}
}
return size
}
fun toByteArray() = getBytes()
/*
* 数据写入方法
*/
fun put(byte: Byte): Unit = write { it.put(byte) }
fun put(char: Char): Unit = write { it.putChar(char) }
fun put(short: Short): Unit = write { it.putShort(short) }
fun put(int: Int): Unit = write { it.putInt(int) }
fun put(long: Long): Unit = write { it.putLong(long) }
fun put(float: Float): Unit = write { it.putFloat(float) }
fun put(double: Double): Unit = write { it.putDouble(double) }
fun put(str: String): Unit = put(str.toByteArray())
fun put(buffer: ByteBuffer): Int = buffer.writeTo(this)
fun put(byteArray: ByteArray, startIndex: Int = 0, endIndex: Int = byteArray.size - startIndex) {
if (hasArray) {
byteArray.copyInto(array, writeOffset, startIndex, endIndex)
writePosition += endIndex - startIndex
} else {
write {
it.put(byteArray, startIndex, endIndex - startIndex)
}
}
}
fun put(array: CharArray, index: Int = 0, size: Int = array.size - index) {
array.forEachIndex(index, index + size - 1, this::put)
}
fun put(array: ShortArray, index: Int = 0, size: Int = array.size - index) {
array.forEachIndex(index, index + size - 1, this::put)
}
fun put(array: IntArray, index: Int = 0, size: Int = array.size - index) {
array.forEachIndex(index, index + size - 1, this::put)
}
fun put(array: LongArray, index: Int = 0, size: Int = array.size - index) {
array.forEachIndex(index, index + size - 1, this::put)
}
fun put(array: FloatArray, index: Int = 0, size: Int = array.size - index) {
array.forEachIndex(index, index + size - 1, this::put)
}
fun put(array: DoubleArray, index: Int = 0, size: Int = array.size - index) {
array.forEachIndex(index, index + size - 1, this::put)
}
fun fill(byte: Byte) {
readPosition = 0
writePosition = 0
write {
while (it.remaining() != 0) {
it.put(byte)
}
}
writePosition = 0
}
fun split(maxSize: Int): Array<out ByteBuffer> {
val size = (((capacity - 1) / maxSize) + 1).and(0x7fff_ffff)
return Array(size) {
if (it != size - 1) {
slice(it * maxSize, maxSize)
} else {
slice(it * maxSize, capacity - it * maxSize)
}
}
}
fun readAllSize(): Int {
val size = readable
readPosition += size
return size
}
}

View File

@ -0,0 +1,79 @@
/**
* 这个文件包含了一些可能出错的操作的封装
* 还有一些是以内联形式封装以提高运行效率
*/
package cn.tursom.core.buffer
import cn.tursom.buffer.MultipleByteBuffer
import cn.tursom.core.buffer.impl.ArrayByteBuffer
import java.nio.channels.SocketChannel
/**
* 使用读 bufferByteBuffer 实现类有义务维护指针正常推进
*/
inline fun <T> ByteBuffer.read(block: (java.nio.ByteBuffer) -> T): T {
val buffer = readBuffer()
return try {
block(buffer)
} finally {
finishRead(buffer)
}
}
/**
* 使用写 bufferByteBuffer 实现类有义务维护指针正常推进
*/
inline fun <T> ByteBuffer.write(block: (java.nio.ByteBuffer) -> T): T {
val buffer = writeBuffer()
return try {
block(buffer)
} finally {
finishWrite(buffer)
}
}
fun SocketChannel.read(buffer: ByteBuffer): Int {
return if (buffer is MultipleByteBuffer) {
buffer.writeBuffers { read(it) }.toInt()
} else {
buffer.write { read(it) }
}
}
fun SocketChannel.write(buffer: ByteBuffer): Int {
return if (buffer is MultipleByteBuffer) {
buffer.readBuffers { write(it) }.toInt()
} else {
buffer.read { write(it) }
}
}
fun SocketChannel.read(buffer: MultipleByteBuffer): Long {
return buffer.writeBuffers { read(it) }
}
fun SocketChannel.write(buffer: MultipleByteBuffer): Long {
return buffer.readBuffers { write(it) }
}
fun SocketChannel.read(buffers: Array<out ByteBuffer>): Long {
val bufferArray = Array(buffers.size) { buffers[it].writeBuffer() }
return try {
read(bufferArray)
} finally {
buffers.forEachIndexed { index, byteBuffer -> byteBuffer.finishWrite(bufferArray[index]) }
}
}
fun SocketChannel.write(buffers: Array<out ByteBuffer>): Long {
val bufferArray = Array(buffers.size) { buffers[it].readBuffer() }
return try {
write(bufferArray)
} finally {
buffers.forEachIndexed { index, byteBuffer -> byteBuffer.finishRead(bufferArray[index]) }
}
}
fun Array<out ByteBuffer>.asMultipleByteBuffer() = ArrayByteBuffer(*this)

View File

@ -0,0 +1,8 @@
package cn.tursom.buffer
import cn.tursom.core.buffer.ByteBuffer
interface MarkableByteBuffer : ByteBuffer {
fun mark()
fun resume()
}

View File

@ -0,0 +1,51 @@
package cn.tursom.buffer
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.ListByteBuffer
import java.io.Closeable
@Suppress("unused")
interface MultipleByteBuffer : List<ByteBuffer>, Closeable {
val buffers: Array<out ByteBuffer> get() = toTypedArray()
/**
* 使用读 bufferByteBuffer 实现类有义务维护指针正常推进
*/
fun <T> readBuffers(block: (Array<out java.nio.ByteBuffer>) -> T): T {
val buffer = readBuffers()
return try {
block(buffer)
} finally {
finishRead(buffer)
}
}
/**
* 使用写 bufferByteBuffer 实现类有义务维护指针正常推进
*/
fun <T> writeBuffers(block: (Array<out java.nio.ByteBuffer>) -> T): T {
val buffer = writeBuffers()
return try {
block(buffer)
} finally {
finishWrite(buffer)
}
}
fun readBuffers(): Array<out java.nio.ByteBuffer> = Array(size) { this[it].readBuffer() }
fun writeBuffers(): Array<out java.nio.ByteBuffer> = Array(size) { this[it].writeBuffer() }
fun finishRead(buffers: Array<out java.nio.ByteBuffer>) = buffers.forEachIndexed { index, byteBuffer ->
this[index].finishRead(byteBuffer)
}
fun finishWrite(buffers: Array<out java.nio.ByteBuffer>) = buffers.forEachIndexed { index, byteBuffer ->
this[index].finishWrite(byteBuffer)
}
override fun close() = forEach(ByteBuffer::close)
fun slice(offset: Int, size: Int): MultipleByteBuffer = ListByteBuffer(subList(offset, offset + size))
fun fill(byte: Byte) = forEach { it.fill(byte) }
fun clear() = forEach(ByteBuffer::clear)
fun reset() = forEach(ByteBuffer::reset)
}

View File

@ -0,0 +1,7 @@
package cn.tursom.buffer
import cn.tursom.core.buffer.ByteBuffer
interface ProxyByteBuffer : ByteBuffer {
val agent: ByteBuffer
}

View File

@ -0,0 +1,8 @@
package cn.tursom.core.buffer.impl
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.buffer.MultipleByteBuffer
class ArrayByteBuffer(
override vararg val buffers: ByteBuffer
) : MultipleByteBuffer, List<ByteBuffer> by buffers.asList()

View File

@ -0,0 +1,8 @@
package cn.tursom.core.buffer.impl
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.buffer.MultipleByteBuffer
class ArrayListByteBuffer : MultipleByteBuffer, MutableList<ByteBuffer> by ArrayList() {
override fun clear() = super.clear()
}

View File

@ -0,0 +1,69 @@
package cn.tursom.core.buffer.impl
import cn.tursom.core.buffer.ByteBuffer
class DirectByteBuffer(private var buffer: java.nio.ByteBuffer) : ByteBuffer {
constructor(size: Int) : this(java.nio.ByteBuffer.allocateDirect(size))
override val hasArray: Boolean = false
override val array: ByteArray get() = buffer.array()
override val capacity: Int get() = buffer.capacity()
override val arrayOffset: Int = 0
override var writePosition: Int = 0
override var readPosition: Int = 0
override var resized: Boolean = false
override fun readBuffer(): java.nio.ByteBuffer {
if (buffer.limit() != writePosition)
buffer.limit(writePosition)
if (buffer.position() != readPosition)
buffer.position(readPosition)
return buffer
}
override fun writeBuffer(): java.nio.ByteBuffer {
if (buffer.limit() != capacity)
buffer.limit(capacity)
if (buffer.position() != writePosition)
buffer.position(writePosition)
return buffer
}
override fun reset() {
buffer.limit(writePosition)
buffer.position(readPosition)
buffer.compact()
readPosition = buffer.position()
writePosition = buffer.limit()
}
override fun slice(offset: Int, size: Int): ByteBuffer {
buffer.limit(offset + size)
buffer.position(offset)
return DirectByteBuffer(buffer.slice())
}
override fun resize(newSize: Int): Boolean {
if (newSize <= buffer.capacity()) return false
resized = true
val newBuf = java.nio.ByteBuffer.allocateDirect(newSize)
newBuf.put(readBuffer())
buffer = newBuf
writePosition = readable
readPosition = 0
return true
}
override fun toString(): String {
return "DirectByteBuffer(buffer=$buffer, hasArray=$hasArray, capacity=$capacity, writePosition=$writePosition, readPosition=$readPosition)"
}
override fun fill(byte: Byte) {
readPosition = 0
writePosition = 0
buffer.clear()
while (buffer.remaining() != 0) {
buffer.put(byte)
}
}
}

View File

@ -0,0 +1,76 @@
package cn.tursom.core.buffer.impl
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.HeapByteBufferUtil
class HeapByteBuffer(private var buffer: java.nio.ByteBuffer) : ByteBuffer {
constructor(size: Int) : this(java.nio.ByteBuffer.allocate(size))
constructor(bytes: ByteArray, offset: Int = 0, size: Int = bytes.size - offset)
: this(HeapByteBufferUtil.wrap(bytes, offset, size)) {
readPosition = offset
writePosition = offset + size
}
init {
assert(buffer.hasArray())
}
override val hasArray: Boolean = true
override val array: ByteArray get() = buffer.array()
override val capacity: Int get() = buffer.capacity()
override val arrayOffset: Int get() = buffer.arrayOffset()
override var writePosition: Int = 0
override var readPosition: Int = 0
override var resized: Boolean = false
override fun readBuffer(): java.nio.ByteBuffer {
if (buffer.limit() != writePosition)
buffer.limit(writePosition)
if (buffer.position() != readPosition)
buffer.position(readPosition)
return buffer
}
override fun writeBuffer(): java.nio.ByteBuffer {
if (buffer.limit() != capacity)
buffer.limit(capacity)
if (buffer.position() != writePosition)
buffer.position(writePosition)
return buffer
}
override fun reset() {
buffer.limit(writePosition)
buffer.position(readPosition)
buffer.compact()
readPosition = buffer.position()
writePosition = buffer.limit()
}
override fun slice(offset: Int, size: Int): ByteBuffer {
buffer.limit(offset + size)
buffer.position(offset)
return HeapByteBuffer(buffer.slice())
}
override fun resize(newSize: Int): Boolean {
if (newSize <= buffer.capacity()) return false
resized = true
val newBuf = java.nio.ByteBuffer.allocate(newSize)
newBuf.put(array, readOffset, readable)
buffer = newBuf
writePosition = readable
readPosition = 0
return true
}
override fun toString(): String {
return "HeapByteBuffer(buffer=$buffer, hasArray=$hasArray, capacity=$capacity, arrayOffset=$arrayOffset, writePosition=$writePosition, readPosition=$readPosition)"
}
override fun fill(byte: Byte) {
writePosition = 0
readPosition = 0
array.fill(byte, arrayOffset, arrayOffset + capacity)
}
}

View File

@ -0,0 +1,20 @@
package cn.tursom.core.buffer.impl
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.buffer.ProxyByteBuffer
import cn.tursom.core.pool.MemoryPool
class InstantByteBuffer(
override val agent: ByteBuffer,
val pool: MemoryPool
) : ProxyByteBuffer, ByteBuffer by agent {
override var closed = false
override fun close() {
agent.close()
pool.free(this)
closed = true
}
override fun toString() = "InstantByteBuffer(agent=$agent)"
}

View File

@ -0,0 +1,6 @@
package cn.tursom.core.buffer.impl
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.buffer.MultipleByteBuffer
class ListByteBuffer(bufferList: List<ByteBuffer>) : MultipleByteBuffer, List<ByteBuffer> by bufferList

View File

@ -0,0 +1,20 @@
package cn.tursom.core.buffer.impl
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.buffer.MarkableByteBuffer
import cn.tursom.buffer.ProxyByteBuffer
class MarkedByteBuffer(override val agent: ByteBuffer) : ProxyByteBuffer, MarkableByteBuffer, ByteBuffer by agent {
private var writeMark = 0
private var readMark = 0
override fun mark() {
writeMark = writePosition
readMark = readPosition
}
override fun resume() {
writePosition = writeMark
readPosition = readMark
}
}

View File

@ -0,0 +1,52 @@
package cn.tursom.core.buffer.impl
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.buffer.ProxyByteBuffer
import cn.tursom.core.pool.MemoryPool
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
/**
* 在被垃圾回收时能保证释放占用的内存池内存
*/
class PooledByteBuffer(
override val agent: ByteBuffer,
val pool: MemoryPool,
val token: Int
) : ProxyByteBuffer, ByteBuffer by agent {
/**
* 这个变量保证 buffer 不会被释放多次
*/
private val open = AtomicBoolean(true)
private val childCount = AtomicInteger(0)
override val resized get() = agent.resized
override val closed: Boolean get() = !open.get() && !resized
override fun close() {
if (childCount.get() == 0) {
if (open.compareAndSet(true, false)) {
pool.free(this)
}
}
}
override fun resize(newSize: Int): Boolean {
val successful = agent.resize(newSize)
if (successful) {
close()
}
return successful
}
override fun slice(offset: Int, size: Int): ByteBuffer {
return SplitByteBuffer(this, childCount, agent.slice(offset, size))
}
override fun toString(): String {
return "PooledByteBuffer(buffer=$agent, pool=$pool, token=$token, open=$open)"
}
protected fun finalize() {
pool.free(this)
}
}

View File

@ -0,0 +1,46 @@
package cn.tursom.core.buffer.impl
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.buffer.ProxyByteBuffer
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
class SplitByteBuffer(
private val parent: ByteBuffer,
private val childCount: AtomicInteger,
override val agent: ByteBuffer
) : ProxyByteBuffer, ByteBuffer by agent {
init {
childCount.incrementAndGet()
}
private val atomicClosed = AtomicBoolean(false)
override val closed: Boolean get() = atomicClosed.get()
override fun close() {
if (atomicClosed.compareAndSet(false, true)) {
agent.close()
childCount.decrementAndGet()
if (childCount.get() == 0 && (parent.closed || parent.resized)) {
parent.close()
}
}
}
override fun slice(offset: Int, size: Int): ByteBuffer {
return SplitByteBuffer(parent, childCount, agent.slice(offset, size))
}
override fun resize(newSize: Int): Boolean {
val successful = agent.resize(newSize)
if (successful) {
close()
}
return successful
}
protected fun finalize() {
close()
}
}

View File

@ -1,445 +0,0 @@
package cn.tursom.core.bytebuffer
import cn.tursom.core.forEachIndex
import cn.tursom.core.logE
import sun.reflect.generics.reflectiveObjects.NotImplementedException
import java.io.OutputStream
import java.nio.ByteBuffer
import kotlin.math.min
interface AdvanceByteBuffer {
val nioBuffer: ByteBuffer
val nioBuffers: Array<out ByteBuffer> get() = arrayOf(nioBuffer)
/**
* 各种位置变量
*/
val readOnly: Boolean
val bufferCount: Int get() = 1
var writePosition: Int
var limit: Int
val capacity: Int
val hasArray: Boolean
val array: ByteArray
val arrayOffset: Int
var readPosition: Int
val readOffset: Int get() = arrayOffset + readPosition
val readableSize: Int
val available: Int get() = readableSize
val writeOffset: Int get() = arrayOffset + writePosition
val writeableSize: Int get() = limit - writePosition
val size: Int
val readMode: Boolean
fun readMode()
fun resumeWriteMode(usedSize: Int = 0)
fun needReadSize(size: Int) {
if (readableSize < size) throw OutOfBufferException()
}
fun useReadSize(size: Int): Int {
needReadSize(size)
readPosition += size
return size
}
fun take(size: Int): Int {
needReadSize(size)
val offset = readOffset
readPosition += size
return offset
}
fun push(size: Int): Int {
val offset = writeOffset
writePosition += size
return offset
}
fun readAllSize() = useReadSize(readableSize)
fun takeAll() = take(readableSize)
fun clear()
fun reset() {
if (hasArray) {
array.copyInto(array, arrayOffset, readOffset, arrayOffset + writePosition)
writePosition = readableSize
readPosition = 0
} else {
readMode()
nioBuffer.compact()
val writePosition = readPosition
resumeWriteMode()
readPosition = 0
this.writePosition = writePosition
}
}
fun reset(outputStream: OutputStream) {
if (hasArray) {
outputStream.write(array, readOffset, arrayOffset + writePosition)
} else {
outputStream.write(getBytes())
}
writePosition = 0
readPosition = 0
}
fun requireAvailableSize(size: Int) {
if (limit - readPosition < size) reset()
}
/*
* 数据获取方法
*/
fun get(): Byte = if (readMode) {
nioBuffer.get()
} else {
readMode()
val value = nioBuffer.get()
resumeWriteMode()
value
}
fun getChar(): Char = if (readMode) {
nioBuffer.char
} else {
readMode()
val value = nioBuffer.char
resumeWriteMode()
value
}
fun getShort(): Short = if (readMode) {
nioBuffer.short
} else {
readMode()
val value = nioBuffer.short
resumeWriteMode()
value
}
fun getInt(): Int = if (readMode) {
nioBuffer.int
} else {
readMode()
val value = nioBuffer.int
resumeWriteMode()
value
}
fun getLong(): Long = if (readMode) {
nioBuffer.long
} else {
readMode()
val value = nioBuffer.long
resumeWriteMode()
value
}
fun getFloat(): Float = if (readMode) {
nioBuffer.float
} else {
readMode()
val value = nioBuffer.float
resumeWriteMode()
value
}
fun getDouble(): Double = if (readMode) {
nioBuffer.double
} else {
readMode()
val value = nioBuffer.double
resumeWriteMode()
value
}
fun getBytes(size: Int = readableSize): ByteArray = if (readMode) {
val bytes = ByteArray(size)
nioBuffer.get(bytes)
readPosition = writePosition
bytes
} else {
readMode()
val bytes = ByteArray(size)
nioBuffer.get(bytes)
readPosition = writePosition
resumeWriteMode()
bytes
}
fun getString(size: Int = readableSize): String = String(getBytes())
fun toString(size: Int): String {
//logE("AdvanceByteBuffer.toString(size: Int): $this")
//val rp = readPosition
val bytes = getBytes(size)
//readPosition = rp
//logE("AdvanceByteBuffer.toString(size: Int): $this")
return String(bytes)
}
fun writeTo(buffer: ByteArray, bufferOffset: Int = 0, size: Int = min(readableSize, buffer.size)): Int {
val readSize = min(readableSize, size)
if (hasArray) {
array.copyInto(buffer, bufferOffset, readOffset, readOffset + readSize)
readPosition += readOffset
reset()
} else {
readBuffer {
it.put(buffer, bufferOffset, readSize)
}
}
return readSize
}
fun writeTo(os: OutputStream): Int {
val size = readableSize
if (hasArray) {
os.write(array, arrayOffset + readPosition, size)
readPosition += size
reset()
} else {
val buffer = ByteArray(1024)
readBuffer {
while (it.remaining() > 0) {
it.put(buffer)
os.write(buffer)
}
}
}
return size
}
fun writeTo(buffer: AdvanceByteBuffer): Int {
val size = min(readableSize, buffer.writeableSize)
if (hasArray && buffer.hasArray) {
array.copyInto(buffer.array, buffer.writeOffset, readOffset, readOffset + size)
buffer.writePosition += size
readPosition += size
reset()
} else {
readBuffer {
buffer.nioBuffer.put(it)
}
}
return size
}
fun toByteArray() = getBytes()
/*
* 数据写入方法
*/
fun put(byte: Byte) {
if (readMode) {
resumeWriteMode()
nioBuffer.put(byte)
readMode()
} else {
nioBuffer.put(byte)
}
}
fun put(char: Char) {
if (readMode) {
resumeWriteMode()
nioBuffer.putChar(char)
readMode()
} else {
nioBuffer.putChar(char)
}
}
fun put(short: Short) {
if (readMode) {
resumeWriteMode()
nioBuffer.putShort(short)
readMode()
} else {
nioBuffer.putShort(short)
}
}
fun put(int: Int) {
if (readMode) {
resumeWriteMode()
nioBuffer.putInt(int)
readMode()
} else {
nioBuffer.putInt(int)
}
}
fun put(long: Long) {
if (readMode) {
resumeWriteMode()
nioBuffer.putLong(long)
readMode()
} else {
nioBuffer.putLong(long)
}
}
fun put(float: Float) {
if (readMode) {
resumeWriteMode()
nioBuffer.putFloat(float)
readMode()
} else {
nioBuffer.putFloat(float)
}
}
fun put(double: Double) {
if (readMode) {
resumeWriteMode()
nioBuffer.putDouble(double)
readMode()
} else {
nioBuffer.putDouble(double)
}
}
fun put(str: String) {
put(str.toByteArray())
}
fun put(byteArray: ByteArray, startIndex: Int = 0, endIndex: Int = byteArray.size - startIndex) {
if (readMode) {
resumeWriteMode()
nioBuffer.put(byteArray, startIndex, endIndex - startIndex)
readMode()
} else {
nioBuffer.put(byteArray, startIndex, endIndex - startIndex)
}
}
fun put(array: CharArray, index: Int = 0, size: Int = array.size - index) {
if (readMode) {
resumeWriteMode()
array.forEachIndex(index, index + size - 1, this::put)
readMode()
} else {
array.forEachIndex(index, index + size - 1, this::put)
}
}
fun put(array: ShortArray, index: Int = 0, size: Int = array.size - index) {
if (readMode) {
resumeWriteMode()
array.forEachIndex(index, index + size - 1, this::put)
readMode()
} else {
array.forEachIndex(index, index + size - 1, this::put)
}
}
fun put(array: IntArray, index: Int = 0, size: Int = array.size - index) {
if (readMode) {
resumeWriteMode()
array.forEachIndex(index, index + size - 1, this::put)
readMode()
} else {
array.forEachIndex(index, index + size - 1, this::put)
}
}
fun put(array: LongArray, index: Int = 0, size: Int = array.size - index) {
if (readMode) {
resumeWriteMode()
array.forEachIndex(index, index + size - 1, this::put)
readMode()
} else {
array.forEachIndex(index, index + size - 1, this::put)
}
}
fun put(array: FloatArray, index: Int = 0, size: Int = array.size - index) {
if (readMode) {
resumeWriteMode()
array.forEachIndex(index, index + size - 1, this::put)
readMode()
} else {
array.forEachIndex(index, index + size - 1, this::put)
}
}
fun put(array: DoubleArray, index: Int = 0, size: Int = array.size - index) {
if (readMode) {
resumeWriteMode()
array.forEachIndex(index, index + size - 1, this::put)
readMode()
} else {
array.forEachIndex(index, index + size - 1, this::put)
}
}
fun peekString(size: Int = readableSize): String {
val readP = readPosition
val str = getString(size)
readPosition = readP
return str
}
fun <T> readBuffer(action: (nioBuffer: ByteBuffer) -> T): T = readNioBuffer(action)
fun <T> writeBuffer(action: (nioBuffer: ByteBuffer) -> T): T = writeNioBuffer(action)
suspend fun <T> readSuspendBuffer(action: suspend (nioBuffer: ByteBuffer) -> T): T = readNioBuffer { action(it) }
suspend fun <T> writeSuspendBuffer(action: suspend (nioBuffer: ByteBuffer) -> T): T = writeNioBuffer { action(it) }
fun split(from: Int = readPosition, to: Int = writePosition): AdvanceByteBuffer {
return if (hasArray) {
ByteArrayAdvanceByteBuffer(array, arrayOffset + readPosition, to - from)
} else {
throw NotImplementedException()
}
}
override fun toString(): String
}
inline fun <T> AdvanceByteBuffer.readNioBuffer(action: (nioBuffer: ByteBuffer) -> T): T {
val readMode = this.readMode
readMode()
val buffer = nioBuffer
val position = readPosition
val bufferPosition = nioBuffer.position()
return try {
//logE(buffer.toString())
action(buffer)
} finally {
if (!readMode) {
resumeWriteMode(buffer.position() - position)
readPosition = position + (buffer.position() - bufferPosition)
}
}
}
inline fun <T> AdvanceByteBuffer.writeNioBuffer(action: (nioBuffer: ByteBuffer) -> T): T {
val readMode = readMode
resumeWriteMode()
val buffer = nioBuffer
val position = writePosition
val bufferPosition = nioBuffer.position()
return try {
action(buffer)
} finally {
if (readMode) {
writePosition = position + (buffer.position() - bufferPosition)
readMode()
}
}
}

View File

@ -1,161 +0,0 @@
package cn.tursom.core.bytebuffer
import cn.tursom.core.*
import java.io.OutputStream
import java.nio.ByteBuffer
class ByteArrayAdvanceByteBuffer(
override val array: ByteArray,
val offset: Int = 0,
override val size: Int = array.size - offset,
override var readPosition: Int = 0,
override var writePosition: Int = size
) : AdvanceByteBuffer {
constructor(size: Int) : this(ByteArray(size), 0, size, 0, 0)
override val hasArray: Boolean get() = true
override var readOnly: Boolean = false
override val nioBuffer: ByteBuffer
get() = if (readMode) readByteBuffer
else writeByteBuffer
override var limit: Int = size
override val capacity: Int get() = size
override val arrayOffset: Int get() = offset
override val available: Int
get() = readableSize
override val writeableSize: Int get() = limit - writePosition
override var readMode: Boolean = false
override fun readMode() {
readMode = true
}
override fun resumeWriteMode(usedSize: Int) {
readPosition += usedSize
readMode = false
}
override fun writeTo(os: OutputStream): Int {
val size = readableSize
os.write(array, readOffset, size)
reset()
return size
}
override val readOffset get() = offset + readPosition
override val writeOffset get() = offset + writePosition
val readByteBuffer get() = HeapByteBuffer.wrap(array, offset + readPosition, writePosition - readPosition)
val writeByteBuffer get() = HeapByteBuffer.wrap(array, offset + writePosition, limit - writePosition)
override val readableSize get() = writePosition - readPosition
val position get() = "ArrayByteBuffer(size=$size, writePosition=$writePosition, readPosition=$readPosition)"
/*
* 位置控制方法
*/
override fun clear() {
writePosition = 0
readPosition = 0
}
override fun reset() {
array.copyInto(array, offset, readOffset, offset + writePosition)
writePosition = readableSize
readPosition = 0
}
override fun reset(outputStream: OutputStream) {
outputStream.write(array, readOffset, offset + writePosition)
writePosition = 0
readPosition = 0
}
override fun needReadSize(size: Int) {
if (readableSize < size) throw OutOfBufferException()
}
override fun take(size: Int): Int {
needReadSize(size)
val offset = readOffset
readPosition += size
return offset
}
override fun useReadSize(size: Int): Int {
needReadSize(size)
readPosition += size
return size
}
override fun push(size: Int): Int {
val offset = writeOffset
writePosition += size
return offset
}
override fun readAllSize() = useReadSize(readableSize)
override fun takeAll() = take(readableSize)
/*
* 数据获取方法
*/
override fun get() = array[take(1)]
override fun getChar() = array.toChar(take(2))
override fun getShort() = array.toShort(take(2))
override fun getInt() = array.toInt(take(4))
override fun getLong() = array.toLong(take(8))
override fun getFloat() = array.toFloat(take(4))
override fun getDouble() = array.toDouble(take(8))
override fun getBytes(size: Int): ByteArray {
val readMode = readMode
readMode()
val array = array.copyOfRange(readPosition, useReadSize(size))
if (!readMode) resumeWriteMode(size)
return array
}
override fun getString(size: Int) = String(array, readPosition, useReadSize(size))
override fun writeTo(buffer: ByteArray, bufferOffset: Int, size: Int): Int {
array.copyInto(buffer, bufferOffset, offset, useReadSize(size))
return size
}
override fun toByteArray() = getBytes()
/*
* 数据写入方法
*/
override fun put(byte: Byte) {
array.put(byte, push(1))
}
override fun put(char: Char) = array.put(char, push(2))
override fun put(short: Short) = array.put(short, push(2))
override fun put(int: Int) = array.put(int, push(4))
override fun put(long: Long) = array.put(long, push(8))
override fun put(float: Float) = array.put(float, push(4))
override fun put(double: Double) = array.put(double, push(8))
override fun put(str: String) = put(str.toByteArray())
override fun put(byteArray: ByteArray, startIndex: Int, endIndex: Int) {
byteArray.copyInto(array, push(endIndex - startIndex), startIndex, endIndex)
}
override fun toString(): String {
//return String(array, readOffset, readableSize)
return "ByteArrayAdvanceByteBuffer(size=$size, readPosition=$readPosition, writePosition=$writePosition)"
}
/**
* 缓冲区用完异常
*/
class OutOfBufferException : Exception()
}

View File

@ -1,68 +0,0 @@
package cn.tursom.core.bytebuffer
import cn.tursom.core.logE
import java.nio.ByteBuffer
class DirectNioAdvanceByteBuffer(val buffer: ByteBuffer) : AdvanceByteBuffer {
override val nioBuffer: ByteBuffer get() = buffer
override val readOnly: Boolean get() = buffer.isReadOnly
var writeMark = 0
override var writePosition: Int
get() {
return if (readMode) writeMark
else buffer.position()
}
set(value) {
if (!readMode) buffer.position(value)
else buffer.limit(value)
}
override var limit: Int = buffer.limit()
get() = if (!readMode) buffer.limit() else field
set(value) {
if (!readMode) buffer.limit(value)
field = value
}
override val capacity: Int get() = buffer.capacity()
override val hasArray: Boolean get() = false
override val array: ByteArray get() = buffer.array()
override val arrayOffset: Int = 0
override var readPosition: Int = 0
get() = if (readMode) buffer.position() else field
set(value) {
if (readMode) buffer.position(value)
field = value
}
override val readableSize: Int get() = if (readMode) buffer.remaining() else writePosition - readPosition
override val size: Int get() = buffer.capacity()
override var readMode: Boolean = false
override fun readMode() {
if (!readMode) {
writeMark = writePosition
//logE("readMode() $this $writeMark $writePosition ${buffer.position()}")
readMode = true
buffer.flip()
buffer.position(readPosition)
//logE("readMode() $this $writeMark $writePosition ${buffer.position()}")
}
}
override fun resumeWriteMode(usedSize: Int) {
if (readMode) {
readMode = false
buffer.limit(capacity)
buffer.position(writeMark)
}
}
override fun clear() {
resumeWriteMode()
buffer.clear()
readPosition = 0
}
override fun toString(): String {
return "DirectNioAdvanceByteBuffer(buffer=$buffer, readMode=$readMode, readPosition=$readPosition, writePosition=$writePosition)"
}
}

View File

@ -1,26 +0,0 @@
package cn.tursom.core.bytebuffer
import java.nio.ByteBuffer
/**
* HOOK java.nio.HeapByteBuffer
*/
object HeapByteBuffer {
private val field = ByteBuffer::class.java.getDeclaredField("offset")
init {
field.isAccessible = true
}
fun wrap(array: ByteArray, offset: Int = 0, size: Int = array.size - offset): ByteBuffer {
val buffer = ByteBuffer.wrap(array, 0, size + offset)
//return if (offset == 0) buffer else {
// buffer.position(offset)
// buffer.slice()
//}
if (offset > 0) field.set(buffer, offset)
return buffer
}
fun wrap(string: String) = wrap(string.toByteArray())
}

View File

@ -1,176 +0,0 @@
package cn.tursom.core.bytebuffer
import cn.tursom.core.*
import java.io.OutputStream
import java.nio.ByteBuffer
@Suppress("unused", "MemberVisibilityCanBePrivate")
class HeapNioAdvanceByteBuffer(val buffer: ByteBuffer) : AdvanceByteBuffer {
constructor(size: Int) : this(ByteBuffer.allocate(size))
constructor(buffer: ByteArray, offset: Int = 0, size: Int = buffer.size - offset) : this(HeapByteBuffer.wrap(buffer, offset, size))
override val nioBuffer: ByteBuffer get() = buffer
override val hasArray: Boolean get() = buffer.hasArray()
override val readOnly: Boolean get() = buffer.isReadOnly
private var _readMode = false
var readMark = 0
var writeMark = 0
/**
* 各种位置变量
*/
override var writePosition
get() = buffer.position()
set(value) {
buffer.position(value)
}
override var limit
get() = buffer.limit()
set(value) {
buffer.limit(value)
}
override val capacity: Int = buffer.capacity()
override val array: ByteArray get() = buffer.array()
override val arrayOffset: Int get() = buffer.arrayOffset()
override var readPosition: Int = 0
override val readOffset get() = arrayOffset + readPosition
override val readableSize get() = writePosition - readPosition
override val available get() = readableSize
override val writeOffset get() = arrayOffset + writePosition
override val writeableSize get() = limit - writePosition
override val size = buffer.capacity()
override val readMode get() = _readMode
/*
* 位置控制方法
*/
override fun readMode() {
writeMark = buffer.position()
readMark = readPosition
buffer.limit(buffer.position())
buffer.position(readPosition)
_readMode = true
}
override fun resumeWriteMode(usedSize: Int) {
readPosition = readMark + usedSize
buffer.limit(buffer.capacity())
buffer.position(writeMark)
_readMode = false
}
override fun needReadSize(size: Int) {
if (readableSize < size) throw OutOfBufferException()
}
override fun useReadSize(size: Int): Int {
needReadSize(size)
readPosition += size
return size
}
override fun take(size: Int): Int {
needReadSize(size)
val offset = readOffset
readPosition += size
return offset
}
override fun push(size: Int): Int {
val offset = writeOffset
writePosition += size
return offset
}
override fun readAllSize() = useReadSize(readableSize)
override fun takeAll() = take(readableSize)
override fun clear() {
readPosition = 0
buffer.clear()
}
override fun reset() {
array.copyInto(array, arrayOffset, readOffset, arrayOffset + writePosition)
writePosition = readableSize
readPosition = 0
}
override fun reset(outputStream: OutputStream) {
outputStream.write(array, readOffset, arrayOffset + writePosition)
writePosition = 0
readPosition = 0
}
override fun requireAvailableSize(size: Int) {
if (limit - readPosition < size) reset()
}
/*
* 数据获取方法
*/
override fun get() = array[take(1)]
override fun getChar() = array.toChar(take(2))
override fun getShort() = array.toShort(take(2))
override fun getInt() = array.toInt(take(4))
override fun getLong() = array.toLong(take(8))
override fun getFloat() = array.toFloat(take(4))
override fun getDouble() = array.toDouble(take(8))
override fun getBytes(size: Int): ByteArray {
val readMode = readMode
readMode()
val array = array.copyOfRange(readPosition, useReadSize(size))
if (!readMode) resumeWriteMode(size)
return array
}
override fun getString(size: Int) = String(array, readOffset, useReadSize(size))
override fun writeTo(buffer: ByteArray, bufferOffset: Int, size: Int): Int {
array.copyInto(buffer, bufferOffset, arrayOffset, useReadSize(size))
return size
}
override fun toByteArray() = getBytes()
/*
* 数据写入方法
*/
override fun put(byte: Byte) {
buffer.put(byte)
}
override fun put(char: Char) = array.put(char, push(2))
override fun put(short: Short) = array.put(short, push(2))
override fun put(int: Int) = array.put(int, push(4))
override fun put(long: Long) = array.put(long, push(8))
override fun put(float: Float) = array.put(float, push(4))
override fun put(double: Double) = array.put(double, push(8))
override fun put(str: String) = put(str.toByteArray())
override fun put(byteArray: ByteArray, startIndex: Int, endIndex: Int) {
byteArray.copyInto(array, push(endIndex - startIndex), startIndex, endIndex)
}
override fun split(from: Int, to: Int): AdvanceByteBuffer {
val readMark = readPosition
val writeMark = writePosition
buffer.position(readMark)
buffer.limit(writeMark)
val slice = HeapNioAdvanceByteBuffer(buffer.slice())
readPosition = readMark
writePosition = writeMark
return slice
}
override fun toString(): String {
return "HeapNioAdvanceByteBuffer(buffer=$buffer, readMode=$_readMode, readMark=$readMark, writeMark=$writeMark, capacity=$capacity, readPosition=$readPosition, size=$size)"
}
}

View File

@ -1,108 +0,0 @@
package cn.tursom.core.bytebuffer
import java.nio.ByteBuffer
import java.util.*
import kotlin.collections.ArrayList
class MultiAdvanceByteBuffer(vararg val buffers: AdvanceByteBuffer) : AdvanceByteBuffer {
init {
resumeWriteMode()
}
var writeBufferIndex = 0
var readBufferIndex = 0
val readBuffer get() = buffers[writeBufferIndex]
val writeBuffer get() = buffers[writeBufferIndex]
val operatorBuffer
get() = if (readMode) {
readBuffer
} else {
writeBuffer
}
override val nioBuffers: Array<out ByteBuffer>
get() {
val bufList = ArrayList<ByteBuffer>()
buffers.forEach { buffer ->
if (buffer.bufferCount == 1) {
bufList.add(buffer.nioBuffer)
} else {
buffer.nioBuffers.forEach {
bufList.add(it)
}
}
}
return bufList.toTypedArray()
}
override val hasArray: Boolean get() = false
override val readOnly: Boolean get() = false
override val bufferCount: Int get() = buffers.size
override val nioBuffer: ByteBuffer get() = operatorBuffer.nioBuffer
override var writePosition: Int
get() = operatorBuffer.writePosition
set(value) {
operatorBuffer.writePosition = value
}
override var limit: Int
get() = operatorBuffer.limit
set(value) {
operatorBuffer.limit = value
}
override val capacity: Int get() = operatorBuffer.capacity
override val array: ByteArray get() = operatorBuffer.array
override val arrayOffset: Int get() = operatorBuffer.arrayOffset
override var readPosition: Int
get() = operatorBuffer.readPosition
set(value) {
operatorBuffer.readPosition = value
}
override val readOffset: Int get() = operatorBuffer.readOffset
override val readableSize: Int get() = operatorBuffer.readableSize
override val available: Int get() = operatorBuffer.available
override val writeOffset: Int get() = operatorBuffer.writeOffset
override val writeableSize: Int get() = operatorBuffer.writeableSize
override val size: Int get() = operatorBuffer.size
override var readMode: Boolean = false
override fun readMode() {
readMode = true
buffers.forEach(AdvanceByteBuffer::readMode)
}
override fun resumeWriteMode(usedSize: Int) {
readMode = false
buffers.forEach { it.resumeWriteMode() }
}
override fun clear() {
writeBufferIndex = 0
readBufferIndex = 0
buffers.forEach { buffer -> buffer.clear() }
}
override fun get(): Byte = readBuffer.get()
override fun getChar(): Char = readBuffer.getChar()
override fun getShort(): Short = readBuffer.getShort()
override fun getInt(): Int = readBuffer.getInt()
override fun getLong(): Long = readBuffer.getLong()
override fun getFloat(): Float = readBuffer.getFloat()
override fun getDouble(): Double = readBuffer.getDouble()
override fun getBytes(size: Int) = readBuffer.getBytes(size)
override fun getString(size: Int): String = readBuffer.getString(size)
override fun put(byte: Byte) = writeBuffer.put(byte)
override fun put(char: Char) = writeBuffer.put(char)
override fun put(short: Short) = writeBuffer.put(short)
override fun put(int: Int) = writeBuffer.put(int)
override fun put(long: Long) = writeBuffer.put(long)
override fun put(float: Float) = writeBuffer.put(float)
override fun put(double: Double) = writeBuffer.put(double)
override fun put(str: String) = writeBuffer.put(str)
override fun toString(): String {
return "MultiAdvanceByteBuffer(buffers=${Arrays.toString(buffers)}, writeBufferIndex=$writeBufferIndex, readBufferIndex=$readBufferIndex, readMode=$readMode)"
}
}

View File

@ -1,10 +0,0 @@
package cn.tursom.core.bytebuffer
import java.nio.ByteBuffer
class NioAdvanceByteBuffer(val buffer: ByteBuffer) :
AdvanceByteBuffer by if (buffer.hasArray()) {
HeapNioAdvanceByteBuffer(buffer)
} else {
DirectNioAdvanceByteBuffer(buffer)
}

View File

@ -1,6 +0,0 @@
package cn.tursom.core.bytebuffer
/**
* 缓冲区用完异常
*/
class OutOfBufferException : Exception()

View File

@ -0,0 +1,62 @@
package cn.tursom.core.pool
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.HeapByteBuffer
import cn.tursom.core.buffer.impl.PooledByteBuffer
import cn.tursom.core.AtomicBitSet
abstract class AbstractMemoryPool(
val blockSize: Int,
val blockCount: Int,
val emptyPoolBuffer: (blockSize: Int) -> ByteBuffer = { HeapByteBuffer(blockSize) },
private val memoryPool: ByteBuffer
) : MemoryPool {
private val bitMap = AtomicBitSet(blockCount.toLong())
val allocated: Int get() = bitMap.trueCount.toInt()
private fun getMemory(token: Int): ByteBuffer = synchronized(this) {
PooledByteBuffer(memoryPool.slice(token * blockSize, blockSize), this, token)
}
/**
* @return token
*/
private fun allocate(): Int {
var index = bitMap.firstDown()
while (index in 0 until blockCount) {
if (bitMap.up(index)) {
return index.toInt()
}
index = if (bitMap[index]) bitMap.firstDown() else index
}
return -1
}
override fun free(memory: ByteBuffer) {
if (memory is PooledByteBuffer && memory.pool == this) {
val token = memory.token
@Suppress("ControlFlowWithEmptyBody")
if (token in 0 until blockCount) while (!bitMap.down(token.toLong()));
}
}
override fun getMemoryOrNull(): ByteBuffer? {
val token = allocate()
return if (token in 0 until blockCount) {
return getMemory(token)
} else {
null
}
}
override fun getMemory(): ByteBuffer = getMemoryOrNull() ?: emptyPoolBuffer(blockSize)
override fun get(blockCount: Int): Array<ByteBuffer> = Array(blockCount) {
val token = allocate()
if (token in 0 until blockCount) {
getMemory(token)
} else {
emptyPoolBuffer(blockSize)
}
}
}

View File

@ -1,43 +0,0 @@
package cn.tursom.core.pool
import cn.tursom.core.datastruct.ArrayBitSet
class ArrayPool<T> : Pool<T> {
private val bitSet = ArrayBitSet(64)
private var poll = Array<Any?>(bitSet.size.toInt()) { null }
override fun put(cache: T): Boolean {
val index = synchronized(bitSet) {
val index = getDown()
bitSet.up(index)
index
}.toInt()
poll[index] = cache
return true
}
override fun get(): T? = synchronized(bitSet) {
val index = bitSet.firstUp()
if (index < 0) null
else {
@Suppress("UNCHECKED_CAST")
val ret = poll[index.toInt()] as T
bitSet.down(index)
ret
}
}
private fun getDown(): Long = synchronized(bitSet) {
val index = bitSet.firstDown()
if (index < 0) {
resize()
bitSet.firstDown()
} else {
index
}
}
private fun resize() {
bitSet.resize(bitSet.size * 2)
}
}

View File

@ -1,10 +0,0 @@
package cn.tursom.core.pool
interface AsyncPool<T> {
suspend fun put(cache: T): Boolean
suspend fun get(): T?
suspend fun <T> AsyncPool<T>.forceGet(): T {
return get() ?: throw Pool.NoCacheException()
}
}

View File

@ -1,37 +0,0 @@
package cn.tursom.core.pool
class CachedLinkedPool<T> : Pool<T> {
@Volatile
private var rootNode: Node<T>? = null
@Volatile
private var cacheNode: Node<T>? = null
override fun put(cache: T): Boolean {
synchronized(this) {
rootNode = if (cacheNode != null) {
val node = cacheNode!!
cacheNode = node.next
node.next = rootNode
rootNode = node
node
} else {
Node(cache, rootNode)
}
}
return true
}
override fun get(): T? {
synchronized(this) {
val node = rootNode
rootNode = rootNode?.next
val value = node?.value
node?.value = null
node?.next = cacheNode
cacheNode = node
return value
}
}
private class Node<T>(var value: T? = null, var next: Node<T>? = null)
}

View File

@ -1,54 +1,21 @@
package cn.tursom.core.pool
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.bytebuffer.NioAdvanceByteBuffer
import cn.tursom.core.datastruct.ArrayBitSet
import java.nio.ByteBuffer
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.DirectByteBuffer
import cn.tursom.core.buffer.impl.HeapByteBuffer
class DirectMemoryPool(override val blockSize: Int = 1024, override val blockCount: Int = 16) : MemoryPool {
private val memoryPool = ByteBuffer.allocateDirect(blockSize * blockCount)
private val bitMap = ArrayBitSet(blockCount.toLong())
/**
* @return token
*/
override fun allocate(): Int = synchronized(this) {
val index = bitMap.firstDown()
if (index in 0 until blockCount) {
bitMap.up(index)
index.toInt()
} else {
-1
}
}
override fun free(token: Int) {
if (token in 0 until blockCount) synchronized(this) {
bitMap.down(token.toLong())
}
}
override fun getMemory(token: Int): ByteBuffer? = if (token in 0 until blockCount) {
synchronized(this) {
memoryPool.limit((token + 1) * blockSize)
memoryPool.position(token * blockSize)
return memoryPool.slice()
}
} else {
null
}
override fun getAdvanceByteBuffer(token: Int): AdvanceByteBuffer? = if (token in 0 until blockCount) {
synchronized(this) {
memoryPool.limit((token + 1) * blockSize)
memoryPool.position(token * blockSize)
return NioAdvanceByteBuffer(memoryPool.slice())
}
} else {
null
}
class DirectMemoryPool(
blockSize: Int = 1024,
blockCount: Int = 16,
emptyPoolBuffer: (blockSize: Int) -> ByteBuffer = { HeapByteBuffer(it) }
) : AbstractMemoryPool(
blockSize,
blockCount,
emptyPoolBuffer,
DirectByteBuffer(java.nio.ByteBuffer.allocateDirect(blockSize * blockCount))
) {
override fun toString(): String {
return "DirectMemoryPool(blockSize=$blockSize, blockCount=$blockCount, bitMap=$bitMap)"
return "DirectMemoryPool(blockSize=$blockSize, blockCount=$blockCount, allocated=$allocated)"
}
}

View File

@ -0,0 +1,69 @@
package cn.tursom.core.pool
import cn.tursom.core.buffer.ByteBuffer
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.atomic.AtomicBoolean
/**
* 可自动申请新内存空间的内存池
* 线程安全
*/
class ExpandableMemoryPool(private val poolFactory: () -> MemoryPool) : MemoryPool {
private val poolList = ConcurrentLinkedQueue<MemoryPool>()
@Volatile
private var usingPool: MemoryPool
private val poolLock = AtomicBoolean(false)
init {
usingPool = poolFactory()
poolList.add(usingPool)
}
/**
* 强制释放所有内存
*/
override fun gc() {
poolList.clear()
usingPool = poolFactory()
poolList.add(usingPool)
}
override fun free(memory: ByteBuffer) = throw NotImplementedError("ExpandableMemoryPool won't allocate any memory")
override fun getMemory(): ByteBuffer {
var buffer = usingPool.getMemoryOrNull()
if (buffer != null) return buffer
poolList.forEach {
val pool = it ?: return@forEach
buffer = pool.getMemoryOrNull()
if (buffer != null) usingPool = pool
return buffer ?: return@forEach
}
return newPool()
}
override fun getMemoryOrNull(): ByteBuffer = getMemory()
override fun toString(): String {
return "ExpandableMemoryPool(poolList=$poolList, usingPool=$usingPool)"
}
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
private fun newPool(): ByteBuffer {
return if (poolLock.compareAndSet(false, true)) {
val newPool = poolFactory()
poolList.add(newPool)
poolLock.set(false)
usingPool = newPool
synchronized(poolLock) {
(poolLock as Object).notifyAll()
}
newPool.getMemory()
} else {
synchronized(poolLock) {
(poolLock as Object).wait(500)
}
poolList.last().getMemory()
}
}
}

View File

@ -1,55 +1,21 @@
package cn.tursom.core.pool
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.bytebuffer.NioAdvanceByteBuffer
import cn.tursom.core.datastruct.ArrayBitSet
import java.nio.ByteBuffer
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.HeapByteBuffer
@Suppress("MemberVisibilityCanBePrivate")
class HeapMemoryPool(override val blockSize: Int = 1024, override val blockCount: Int = 16) : MemoryPool {
private val memoryPool = ByteBuffer.allocate(blockSize * blockCount)
private val bitMap = ArrayBitSet(blockCount.toLong())
/**
* @return token
*/
override fun allocate(): Int = synchronized(this) {
val index = bitMap.firstDown()
if (index in 0 until blockCount) {
bitMap.up(index)
index.toInt()
} else {
-1
}
}
override fun free(token: Int) {
if (token in 0 until blockCount) synchronized(this) {
bitMap.down(token.toLong())
}
}
override fun getMemory(token: Int): ByteBuffer? = if (token in 0 until blockCount) {
synchronized(this) {
memoryPool.limit((token + 1) * blockSize)
memoryPool.position(token * blockSize)
return memoryPool.slice()
}
} else {
null
}
override fun getAdvanceByteBuffer(token: Int): AdvanceByteBuffer? = if (token in 0 until blockCount) {
synchronized(this) {
memoryPool.limit((token + 1) * blockSize)
memoryPool.position(token * blockSize)
return NioAdvanceByteBuffer(memoryPool.slice())
}
} else {
null
}
override fun toString(): String {
return "HeapMemoryPool(blockSize=$blockSize, blockCount=$blockCount, bitMap=$bitMap)"
}
class HeapMemoryPool(
blockSize: Int = 1024,
blockCount: Int = 16,
emptyPoolBuffer: (blockSize: Int) -> ByteBuffer = { HeapByteBuffer(it) }
) : AbstractMemoryPool(
blockSize,
blockCount,
emptyPoolBuffer,
HeapByteBuffer(java.nio.ByteBuffer.allocate(blockSize * blockCount))
) {
override fun toString(): String {
return "HeapMemoryPool(blockSize=$blockSize, blockCount=$blockCount, allocated=$allocated)"
}
}

View File

@ -0,0 +1,34 @@
package cn.tursom.core.pool
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.HeapByteBuffer
import cn.tursom.core.buffer.impl.InstantByteBuffer
import java.lang.ref.SoftReference
import java.util.concurrent.ConcurrentLinkedQueue
class InstantMemoryPool(
val blockSize: Int,
val newMemory: (blockSize: Int) -> ByteBuffer = { HeapByteBuffer(blockSize) }
) : MemoryPool {
private val memoryList = ConcurrentLinkedQueue<SoftReference<InstantByteBuffer>>()
override fun free(memory: ByteBuffer) {
if (memory is InstantByteBuffer && memory.pool == this && !memory.closed) {
memory.closed = true
memoryList.add(SoftReference(memory))
}
}
override fun getMemory(): ByteBuffer = getMemoryOrNull() ?: InstantByteBuffer(newMemory(blockSize), this)
override fun getMemoryOrNull(): ByteBuffer? {
memoryList.forEach {
return it.get() ?: return@forEach
}
return null
}
override fun toString(): String {
return "InstantMemoryPool(blockSize=$blockSize, memoryList=${memoryList.size})"
}
}

View File

@ -1,23 +1,23 @@
package cn.tursom.core.pool
class LinkedPool<T> : Pool<T> {
@Volatile
private var rootNode: Node<T>? = null
override fun put(cache: T): Boolean {
synchronized(this) {
rootNode = Node(cache, rootNode)
}
return true
}
override fun get(): T? {
synchronized(this) {
val node = rootNode
rootNode = rootNode?.next
return node?.value
}
}
private class Node<T>(var value: T? = null, var next: Node<T>? = null)
@Volatile
private var rootNode: Node<T>? = null
override fun put(cache: T): Boolean {
synchronized(this) {
rootNode = Node(cache, rootNode)
}
return true
}
override fun get(): T? {
synchronized(this) {
val node = rootNode
rootNode = rootNode?.next
return node?.value
}
}
private class Node<T>(var value: T? = null, var next: Node<T>? = null)
}

View File

@ -0,0 +1,69 @@
package cn.tursom.core.pool
import cn.tursom.core.LongBitSet
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.HeapByteBuffer
import cn.tursom.core.buffer.impl.PooledByteBuffer
/**
* 无锁固定容量的内存池
*/
abstract class LongBitSetAbstractMemoryPool(
val blockSize: Int,
val emptyPoolBuffer: (blockSize: Int) -> ByteBuffer = { HeapByteBuffer(blockSize) },
private val memoryPool: ByteBuffer
) : MemoryPool {
private val bitMap = LongBitSet()
val allocated: Int get() = bitMap.trueCount.toInt()
val blockCount: Int get() = 64
init {
assert(memoryPool.capacity >= 64 * blockSize)
}
private fun getMemory(token: Int): ByteBuffer = synchronized(this) {
return PooledByteBuffer(memoryPool.slice(token * blockSize, blockSize), this, token)
}
/**
* @return token
*/
private fun allocate(): Int {
var index = bitMap.firstDown()
while (index >= 0) {
if (bitMap.up(index)) {
return index
}
index = bitMap.firstDown()
}
return index
}
override fun free(memory: ByteBuffer) {
if (memory is PooledByteBuffer && memory.pool == this) {
val token = memory.token
@Suppress("ControlFlowWithEmptyBody")
if (token >= 0) while (!bitMap.down(token));
}
}
override fun getMemoryOrNull(): ByteBuffer? {
val token = allocate()
return if (token >= 0) {
return getMemory(token)
} else {
null
}
}
override fun getMemory(): ByteBuffer = getMemoryOrNull() ?: emptyPoolBuffer(blockSize)
override fun get(blockCount: Int): Array<ByteBuffer> = Array(blockCount) {
val token = allocate()
if (token in 0 until blockCount) {
getMemory(token)
} else {
emptyPoolBuffer(blockSize)
}
}
}

View File

@ -0,0 +1,13 @@
package cn.tursom.core.pool
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.DirectByteBuffer
class LongBitSetDirectMemoryPool(
blockSize: Int,
emptyPoolBuffer: (blockSize: Int) -> ByteBuffer = { DirectByteBuffer(it) }
) : LongBitSetAbstractMemoryPool(blockSize, emptyPoolBuffer, DirectByteBuffer(64 * blockSize)) {
override fun toString(): String {
return "LongBitSetDirectMemoryPool(blockSize=$blockSize, blockCount=$blockCount, allocated=$allocated)"
}
}

View File

@ -0,0 +1,13 @@
package cn.tursom.core.pool
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.HeapByteBuffer
class LongBitSetHeapMemoryPool (
blockSize: Int,
emptyPoolBuffer: (blockSize: Int) -> ByteBuffer = { HeapByteBuffer(it) }
) : LongBitSetAbstractMemoryPool(blockSize, emptyPoolBuffer, HeapByteBuffer(64 * blockSize)) {
override fun toString(): String {
return "LongBitSetDirectMemoryPool(blockSize=$blockSize, blockCount=$blockCount, allocated=$allocated)"
}
}

View File

@ -0,0 +1,47 @@
package cn.tursom.core.pool
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.PooledByteBuffer
import java.io.Closeable
/**
* 可以记录与释放分配内存的内存池
* 在被垃圾回收时能自动回收内存池的内存
* 是一次性用品
* 非线程安全
*/
class MarkedMemoryPool(private val pool: MemoryPool) : MemoryPool by pool, Closeable {
private val allocatedList = ArrayList<ByteBuffer>(2)
override fun getMemory(): ByteBuffer {
val memory = pool.getMemory()
allocatedList.add(memory)
return memory
}
override fun getMemoryOrNull(): ByteBuffer? {
val memory = pool.getMemoryOrNull()
if (memory != null) allocatedList.add(memory)
return memory
}
override fun close() {
allocatedList.forEach(ByteBuffer::close)
allocatedList.clear()
}
override fun gc() {
pool.gc()
}
override fun toString(): String {
val allocated = ArrayList<Int>(allocatedList.size)
allocatedList.forEach {
if (it is PooledByteBuffer && !it.closed) allocated.add(it.token)
}
return "MarkedMemoryPool(pool=$pool, allocated=$allocated)"
}
protected fun finalize() {
close()
}
}

View File

@ -1,47 +1,30 @@
package cn.tursom.core.pool
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.bytebuffer.NioAdvanceByteBuffer
import java.nio.ByteBuffer
import cn.tursom.core.buffer.ByteBuffer
/**
* 内存池提供批量的等大小的 ByteBuffer
* 使用 allocate 分配内存使用 getMemory getAdvanceByteBuffer 获得内存使用 free 释放内存
* 内存池
*/
interface MemoryPool {
val blockSize: Int
val blockCount: Int
fun allocate(): Int
fun free(token: Int)
fun getMemory(token: Int): ByteBuffer?
fun getAdvanceByteBuffer(token: Int): AdvanceByteBuffer? {
val buffer = getMemory(token)
return if (buffer != null) {
NioAdvanceByteBuffer(buffer)
} else {
null
val staticSize: Boolean get() = true
// fun allocate(): Int
fun free(memory: ByteBuffer)
fun getMemory(): ByteBuffer
fun getMemoryOrNull(): ByteBuffer?
override fun toString(): String
suspend operator fun <T> invoke(action: suspend (ByteBuffer) -> T): T {
return getMemory().use { buffer ->
action(buffer)
}
}
override fun toString(): String
fun get() = getMemory()
operator fun get(blockCount: Int): Array<ByteBuffer> = Array(blockCount) { get() }
fun gc() {}
}
inline fun <T> MemoryPool.usingMemory(action: (ByteBuffer?) -> T): T {
val token = allocate()
return try {
action(getMemory(token))
} finally {
free(token)
}
}
inline fun <T> MemoryPool.usingAdvanceByteBuffer(action: (AdvanceByteBuffer?) -> T): T {
val token = allocate()
return try {
action(getAdvanceByteBuffer(token))
} finally {
free(token)
}
}

View File

@ -1,12 +1,12 @@
package cn.tursom.core.pool
interface Pool<T> {
fun put(cache: T): Boolean
fun get(): T?
class NoCacheException : Exception()
fun <T> Pool<T>.forceGet(): T {
return get() ?: throw NoCacheException()
}
}
fun put(cache: T): Boolean
fun get(): T?
class NoCacheException : Exception()
fun <T> Pool<T>.forceGet(): T {
return get() ?: throw NoCacheException()
}
}

View File

@ -0,0 +1,76 @@
package cn.tursom.core.pool
import cn.tursom.core.buffer.ByteBuffer
import java.lang.ref.SoftReference
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.atomic.AtomicBoolean
/**
* 利用 GC 进行内存释放的内存池
*/
class ScalabilityMemoryPool(private val poolFactory: () -> MemoryPool) : MemoryPool {
private val poolList = ConcurrentLinkedQueue<SoftReference<MemoryPool>>()
@Volatile
private var usingPool: MemoryPool
private val poolLock = AtomicBoolean(false)
init {
usingPool = poolFactory()
poolList.add(SoftReference(usingPool))
}
/**
* 释放所有被 gc 释放的内存
*/
override fun gc() {
val iterator = poolList.iterator()
iterator.forEach {
if (it.get() == null) {
iterator.remove()
}
}
}
override fun free(memory: ByteBuffer) = throw NotImplementedError("ExpandableMemoryPool won't allocate any memory")
override fun getMemory(): ByteBuffer {
var buffer = usingPool.getMemoryOrNull()
if (buffer != null) return buffer
val iterator = poolList.iterator()
iterator.forEach {
val pool = it.get() ?: run {
iterator.remove()
return@forEach
}
buffer = pool.getMemoryOrNull()
if (buffer != null) usingPool = pool
return buffer ?: return@forEach
}
return newPool()
}
override fun getMemoryOrNull(): ByteBuffer = getMemory()
override fun toString(): String {
return "ScalabilityMemoryPool(poolList=$poolList, usingPool=$usingPool)"
}
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
private fun newPool(): ByteBuffer {
return if (poolLock.compareAndSet(false, true)) {
val newPool = poolFactory()
poolList.add(SoftReference(newPool))
poolLock.set(false)
usingPool = newPool
synchronized(poolLock) {
(poolLock as Object).notifyAll()
}
newPool.getMemory()
} else {
synchronized(poolLock) {
(poolLock as Object).wait(500)
}
usingPool.getMemory()
}
}
}

View File

@ -0,0 +1,30 @@
package cn.tursom.core.pool
import cn.tursom.core.buffer.ByteBuffer
class ThreadLocalMemoryPool(private val poolFactory: () -> MemoryPool) : MemoryPool {
private val threadLocal = ThreadLocal<MemoryPool>()
override fun free(memory: ByteBuffer) = throw NotImplementedError("ThreadLocalMemoryPool won't allocate any memory")
override fun getMemory(): ByteBuffer = getPool().getMemory()
override fun getMemoryOrNull(): ByteBuffer? = getPool().getMemoryOrNull()
override fun toString(): String {
return "ThreadLocalMemoryPool(threadLocal=$threadLocal)"
}
override fun gc() {
threadLocal.get()?.gc()
}
private fun getPool(): MemoryPool {
var pool = threadLocal.get()
if (pool == null) {
pool = poolFactory()
threadLocal.set(pool)
}
return pool
}
}

View File

@ -0,0 +1,68 @@
package cn.tursom.core.pool
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.HeapByteBuffer
import cn.tursom.core.buffer.impl.PooledByteBuffer
import cn.tursom.core.datastruct.ArrayBitSet
abstract class ThreadUnsafeAbstractMemoryPool(
val blockSize: Int,
val blockCount: Int,
val emptyPoolBuffer: (blockSize: Int) -> ByteBuffer = { HeapByteBuffer(blockSize) },
private val memoryPool: ByteBuffer
) : MemoryPool {
private val bitMap = ArrayBitSet(blockCount.toLong())
val allocated: Int get() = bitMap.trueCount.toInt()
private fun unsafeAllocate(): Int {
val index = bitMap.firstDown()
return if (index in 0 until blockCount) {
bitMap.up(index)
index.toInt()
} else {
-1
}
}
private fun unsafeFree(token: Int) {
bitMap.down(token.toLong())
}
private fun unsafeGetMemory(token: Int): ByteBuffer {
return PooledByteBuffer(memoryPool.slice(token * blockSize, blockSize), this, token)
}
/**
* @return token
*/
private fun allocate(): Int = unsafeAllocate()
override fun free(memory: ByteBuffer) {
if (memory is PooledByteBuffer && memory.pool == this) {
val token = memory.token
if (token in 0 until blockCount) unsafeFree(token)
}
}
override fun getMemoryOrNull(): ByteBuffer? {
val token = allocate()
return if (token in 0 until blockCount) {
unsafeGetMemory(token)
} else {
null
}
}
override fun getMemory(): ByteBuffer = getMemoryOrNull() ?: emptyPoolBuffer(blockSize)
override fun get(blockCount: Int): Array<ByteBuffer> = synchronized(this) {
Array(blockCount) {
val token = unsafeAllocate()
if (token in 0 until blockCount) {
unsafeGetMemory(token)
} else {
emptyPoolBuffer(blockSize)
}
}
}
}

View File

@ -0,0 +1,21 @@
package cn.tursom.core.pool
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.DirectByteBuffer
import cn.tursom.core.buffer.impl.HeapByteBuffer
class ThreadUnsafeDirectMemoryPool(
blockSize: Int = 1024,
blockCount: Int = 16,
emptyPoolBuffer: (blockSize: Int) -> ByteBuffer = { HeapByteBuffer(it) }
) : ThreadUnsafeAbstractMemoryPool(
blockSize,
blockCount,
emptyPoolBuffer,
DirectByteBuffer(java.nio.ByteBuffer.allocateDirect(blockSize * blockCount))
) {
override fun toString(): String {
return "DirectMemoryPool(blockSize=$blockSize, blockCount=$blockCount, allocated=$allocated)"
}
}

View File

@ -0,0 +1,21 @@
package cn.tursom.core.pool
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.HeapByteBuffer
@Suppress("MemberVisibilityCanBePrivate")
class ThreadUnsafeHeapMemoryPool(
blockSize: Int = 1024,
blockCount: Int = 16,
emptyPoolBuffer: (blockSize: Int) -> ByteBuffer = { HeapByteBuffer(it) }
) : ThreadUnsafeAbstractMemoryPool(
blockSize,
blockCount,
emptyPoolBuffer,
HeapByteBuffer(java.nio.ByteBuffer.allocate(blockSize * blockCount))
) {
override fun toString(): String {
return "ThreadUnsafeHeapMemoryPool(blockSize=$blockSize, blockCount=$blockCount, allocated=$allocated)"
}
}

View File

@ -0,0 +1,55 @@
package cn.tursom.core.timer
import cn.tursom.core.CurrentTimeMillisClock
import java.util.concurrent.atomic.AtomicReference
class NonLockTaskQueue : TaskQueue {
private val root = AtomicReference<TaskListNode?>()
private fun add(taskNode: TaskListNode): TaskListNode {
while (!root.compareAndSet(taskNode.next, taskNode)) {
taskNode.next = root.get()
}
return taskNode
}
override fun offer(task: () -> Unit, timeout: Long): TimerTask {
return add(TaskListNode(timeout, task, CurrentTimeMillisClock.now, root.get()))
}
override fun offer(task: TimerTask): TimerTask {
if (task.canceled || task.isOutTime) return task
return if (task is TaskListNode) {
add(task)
} else {
add(TaskListNode(task.timeout, task.task, task.createTime, root.get()))
}
}
override fun take(): TimerTask? {
var node = root.get()
while (!root.compareAndSet(node, node?.next)) {
node = root.get()
}
return node
}
private class TaskListNode(
override val timeout: Long,
override val task: () -> Unit,
override val createTime: Long,
@Volatile var next: TaskListNode?
) : TimerTask {
@Volatile
override var canceled: Boolean = false
override val outTime: Long = super.outTime
override fun invoke() {
task()
}
override fun cancel() {
canceled = true
}
}
}

View File

@ -1,102 +0,0 @@
package cn.tursom.core.timer
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.ThreadFactory
import kotlin.concurrent.thread
class StaticWheelTimer(
val tick: Long = 200,
val wheelSize: Int = 512
) : Timer {
var closed = false
val taskQueueArray = Array(wheelSize) { TaskQueue() }
private var position = 0
override fun exec(timeout: Long, task: () -> Unit): TimerTask {
val index = ((timeout / tick + position + if (timeout % tick == 0L) 0 else 1) % wheelSize).toInt()
return taskQueueArray[index].offer(task, timeout)
}
init {
thread(isDaemon = true) {
while (!closed) {
position %= wheelSize
val newQueue = TaskQueue()
val taskQueue = taskQueueArray[position]
taskQueueArray[position] = newQueue
val time = System.currentTimeMillis()
var node = taskQueue.root
while (node != null) {
node = if (node.isOutTime(time)) {
if (!node.canceled) threadPool.execute(node.task)
node.next
} else {
val next = node.next
newQueue.offer(node)
next
}
}
position++
Thread.sleep(tick)
}
}
}
class TaskQueue {
var root: TaskNode? = null
fun offer(task: () -> Unit, timeout: Long): TaskNode {
synchronized(this) {
val insert = TaskNode(timeout, task, root)
root = insert
return insert
}
}
fun offer(node: TaskNode): TaskNode {
synchronized(this) {
node.next = root
root = node
return node
}
}
inner class TaskNode(
val timeout: Long,
val task: () -> Unit,
var next: TaskNode?,
var canceled: Boolean = false
) : TimerTask {
val outTime = System.currentTimeMillis() + timeout
val isOutTime get() = System.currentTimeMillis() > outTime
fun isOutTime(time: Long) = time > outTime
override fun run() = task()
override fun cancel() {
canceled = true
}
}
}
companion object {
val threadPool: ExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(),
object : ThreadFactory {
var threadNumber = 0
override fun newThread(r: Runnable): Thread {
val thread = Thread(r)
thread.isDaemon = true
thread.name = "staticWheelTimerWorker-$threadNumber"
return thread
}
})
val timer by lazy { StaticWheelTimer(100, 1024) }
val smoothTimer by lazy { StaticWheelTimer(20, 128) }
}
}

View File

@ -0,0 +1,69 @@
package cn.tursom.core.timer
import cn.tursom.core.CurrentTimeMillisClock
class SynchronizedTaskQueue : TaskQueue {
val root: TaskNode = TaskNode(0, {}, null, null)
private fun offer(task: () -> Unit, timeout: Long, createTime: Long): TaskNode {
synchronized(root) {
val insert = TaskNode(timeout, task, root, root.next, createTime)
root.next = insert
insert.next?.prev = insert
return insert
}
}
override fun offer(task: () -> Unit, timeout: Long): TaskNode {
return offer(task, timeout, CurrentTimeMillisClock.now)
}
override fun offer(task: TimerTask): TimerTask {
return if (task is TaskNode) {
synchronized(root) {
task.next = root.next
task.next = task
task.next?.prev = task
task
}
} else {
offer(task.task, task.timeout, task.createTime)
}
}
override fun take(): TimerTask? {
synchronized(root) {
val node = root.next
root.next = node?.next
return node
}
}
inner class TaskNode(
override val timeout: Long,
override val task: () -> Unit,
@Volatile var prev: TaskNode?,
@Volatile var next: TaskNode?,
override val createTime: Long = CurrentTimeMillisClock.now
) : TimerTask {
@Volatile
override var canceled: Boolean = false
get() = synchronized(root) {
field
}
override val outTime = createTime + timeout
override fun invoke() {
task()
}
override fun cancel() {
synchronized(root) {
canceled = true
prev?.next = next
next?.prev = prev
}
}
}
}

View File

@ -0,0 +1,7 @@
package cn.tursom.core.timer
interface TaskQueue {
fun offer(task: () -> Unit, timeout: Long): TimerTask
fun offer(task: TimerTask): TimerTask
fun take(): TimerTask?
}

View File

@ -1,5 +1,41 @@
package cn.tursom.core.timer
import java.util.concurrent.*
interface Timer {
fun exec(timeout: Long, task: () -> Unit): TimerTask
fun exec(timeout: Long, task: () -> Unit): TimerTask
fun runNow(task: () -> Unit) {
threadPool.execute(task)
}
fun runNow(taskList: TaskQueue) {
threadPool.execute {
while (true) {
val task = taskList.take() ?: return@execute
try {
task()
} catch (e: Throwable) {
e.printStackTrace()
}
}
}
}
companion object {
private val threadPool: ExecutorService = ThreadPoolExecutor(
Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors(),
0L, TimeUnit.MILLISECONDS,
LinkedTransferQueue(),
object : ThreadFactory {
var threadNumber = 0
override fun newThread(r: Runnable): Thread {
val thread = Thread(r)
thread.isDaemon = true
thread.name = "timer-worker-$threadNumber"
return thread
}
})
}
}

View File

@ -1,6 +1,15 @@
package cn.tursom.core.timer
interface TimerTask {
fun run()
fun cancel()
import cn.tursom.core.CurrentTimeMillisClock
interface TimerTask : () -> Unit {
val canceled: Boolean
val createTime: Long
val timeout: Long
val task: () -> Unit
val outTime get() = createTime + timeout
val isOutTime get() = CurrentTimeMillisClock.now > outTime
fun isOutTime(time: Long): Boolean = time > outTime
fun cancel()
}

View File

@ -1,112 +1,93 @@
package cn.tursom.core.timer
import cn.tursom.core.CurrentTimeMillisClock
import java.lang.Thread.sleep
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.ThreadFactory
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.ScheduledThreadPoolExecutor
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicReferenceArray
import kotlin.concurrent.thread
@Suppress("CanBeParameter", "MemberVisibilityCanBePrivate")
class WheelTimer(
val tick: Long = 200,
val wheelSize: Int = 512
val wheelSize: Int = 512,
val name: String = "wheelTimerLooper",
val taskQueueFactory: () -> TaskQueue = { NonLockTaskQueue() }
) : Timer {
var closed = false
val taskQueueArray = Array(wheelSize) { TaskQueue() }
val taskQueueArray = AtomicReferenceArray(Array(wheelSize) { taskQueueFactory() })
@Volatile
private var position = 0
override fun exec(timeout: Long, task: () -> Unit): TimerTask {
val index = ((timeout / tick + position + if (timeout % tick == 0L) 0 else 1) % wheelSize).toInt()
//val index = ((timeout / tick + position + if (timeout % tick == 0L) 0 else 1) % wheelSize).toInt()
val index = ((timeout / tick + position) % wheelSize).toInt()
return taskQueueArray[index].offer(task, timeout)
}
init {
thread(isDaemon = true, name = "wheelTimerLooper") {
val startTime = System.currentTimeMillis()
//ScheduledThreadPoolExecutor(1) { runnable ->
// val thread = Thread(runnable, name)
// thread.isDaemon = true
// thread
//}.scheduleAtFixedRate(tick, tick, TimeUnit.MILLISECONDS) {
// val outTimeQueue = taskQueueFactory()
// val newQueue = taskQueueFactory()
// val taskQueue = taskQueueArray.getAndSet(position++, newQueue)
// position %= wheelSize
// while (true) {
// val task = taskQueue.take() ?: break
// if (task.canceled) {
//
// continue
// } else if (task.isOutTime) {
// outTimeQueue.offer(task)
// } else {
// newQueue.offer(task)
// }
// }
//
// runNow(outTimeQueue)
//}
thread(isDaemon = true, name = name) {
val startTime = CurrentTimeMillisClock.now
while (!closed) {
position %= wheelSize
val newQueue = TaskQueue()
val taskQueue = taskQueueArray[position]
taskQueueArray[position] = newQueue
val time = System.currentTimeMillis()
var node = taskQueue.root.next
while (node != null) {
node = if (node.isOutTime(time)) {
val sNode = node
threadPool.execute { sNode.task() }
node.next
val outTimeQueue = taskQueueFactory()
val newQueue = taskQueueFactory()
val taskQueue = taskQueueArray.getAndSet(position++, newQueue)
while (true) {
val node = taskQueue.take() ?: break
if (node.canceled) {
continue
} else if (node.isOutTime) {
outTimeQueue.offer(node)
//runNow(node)
} else {
val next = node.next
newQueue.offer(node)
next
}
}
position++
val nextSleep = startTime + tick * position - System.currentTimeMillis()
runNow(outTimeQueue)
val nextSleep = startTime + tick * position - CurrentTimeMillisClock.now
if (nextSleep > 0) sleep(tick)
}
}
}
class TaskQueue {
val root: TaskNode = TaskNode(0, {}, null, null)
fun offer(task: () -> Unit, timeout: Long): TaskNode {
synchronized(root) {
val insert = TaskNode(timeout, task, root, root.next)
root.next = insert
insert.next?.prev = insert
return insert
}
}
fun offer(node: TaskNode): TaskNode {
synchronized(root) {
node.next = root.next
node.next = node
node.next?.prev = node
return node
}
}
inner class TaskNode(
val timeout: Long,
val task: () -> Unit,
var prev: TaskNode?,
var next: TaskNode?
) : TimerTask {
val outTime = System.currentTimeMillis() + timeout
val isOutTime get() = System.currentTimeMillis() > outTime
fun isOutTime(time: Long) = time > outTime
override fun run() = task()
override fun cancel() {
synchronized(root) {
prev?.next = next
next?.prev = prev
}
}
}
}
companion object {
val threadPool: ExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(),
object : ThreadFactory {
var threadNumber = 0
override fun newThread(r: Runnable): Thread {
val thread = Thread(r)
thread.isDaemon = true
thread.name = "wheelTimerWorker-$threadNumber"
return thread
}
})
val timer by lazy { WheelTimer(200, 1024) }
val smoothTimer by lazy { WheelTimer(20, 128) }
fun ScheduledThreadPoolExecutor.scheduleAtFixedRate(
var2: Long,
var4: Long,
var6: TimeUnit,
var1: () -> Unit
): ScheduledFuture<*> = scheduleAtFixedRate(var1, var2, var4, var6)
}
}

View File

@ -9,13 +9,13 @@ package cn.tursom.utils.bytebuffer
* will support
*/
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.isStatic
import cn.tursom.core.unsafe
class UnsupportedException : Exception()
fun AdvanceByteBuffer.serialize(obj: Any) {
fun ByteBuffer.serialize(obj: Any) {
when (obj) {
is Char -> put(obj)
is Short -> put(obj)
@ -80,7 +80,7 @@ fun AdvanceByteBuffer.serialize(obj: Any) {
}
@Suppress("UNCHECKED_CAST")
fun <T> AdvanceByteBuffer.unSerialize(clazz: Class<T>): T {
fun <T> ByteBuffer.unSerialize(clazz: Class<T>): T {
when {
clazz == Byte::class.java -> {
return get() as T
@ -188,6 +188,7 @@ fun <T> AdvanceByteBuffer.unSerialize(clazz: Class<T>): T {
return newArray as T
}
else -> {
//TODO
val instance = try {
clazz.newInstance()
} catch (e: Throwable) {
@ -203,6 +204,6 @@ fun <T> AdvanceByteBuffer.unSerialize(clazz: Class<T>): T {
}
}
inline fun <reified T : Any> AdvanceByteBuffer.unSerialize(): T {
inline fun <reified T : Any> ByteBuffer.unSerialize(): T {
return unSerialize(T::class.java)
}

View File

@ -1,49 +0,0 @@
package cn.tursom.utils.pool
import cn.tursom.core.datastruct.ArrayBitSet
import cn.tursom.core.pool.AsyncPool
import cn.tursom.utils.asynclock.AsyncLock
import cn.tursom.utils.asynclock.AsyncMutexLock
class AsyncArrayPool<T>(private val lock: AsyncLock = AsyncMutexLock()) : AsyncPool<T> {
private val bitSet = ArrayBitSet(64)
private var poll = Array<Any?>(bitSet.size.toInt()) { null }
override suspend fun put(cache: T): Boolean {
val index = lock {
val index = getDown()
bitSet.up(index)
index
}.toInt()
poll[index] = cache
return true
}
override suspend fun get(): T? {
return lock {
val index = bitSet.firstUp()
if (index < 0) null
else {
@Suppress("UNCHECKED_CAST")
val ret = poll[index.toInt()] as T
bitSet.down(index)
ret
}
}
}
private fun getDown(): Long {
val index = bitSet.firstDown()
return if (index < 0) {
resize()
bitSet.firstDown()
} else {
index
}
}
private fun resize() {
bitSet.resize(bitSet.size * 2)
}
}

View File

@ -1,40 +0,0 @@
package cn.tursom.utils.pool
import cn.tursom.core.pool.AsyncPool
import cn.tursom.utils.asynclock.AsyncMutexLock
/**
* 这个缓冲池不会释放自己持有的节点资源防止频繁分配对象导致性能下降
*/
class AsyncCachedLinkedPool<T> : AsyncPool<T> {
@Volatile
private var rootNode: Node<T>? = null
@Volatile
private var cacheNode: Node<T>? = null
private val lock = AsyncMutexLock()
override suspend fun put(cache: T): Boolean = lock {
rootNode = if (cacheNode != null) {
val node = cacheNode!!
cacheNode = node.next
node.next = rootNode
rootNode = node
node
} else {
Node(cache, rootNode)
}
true
}
override suspend fun get(): T? = lock {
val node = rootNode
rootNode = rootNode?.next
val value = node?.value
node?.value = null
node?.next = cacheNode
cacheNode = node
value
}
private class Node<T>(var value: T? = null, var next: Node<T>? = null)
}

View File

@ -1,23 +0,0 @@
package cn.tursom.utils.pool
import cn.tursom.core.pool.AsyncPool
import cn.tursom.utils.asynclock.AsyncMutexLock
class AsyncLinkedCachePool<T> : AsyncPool<T> {
@Volatile
private var rootNode: Node<T>? = null
private val lock = AsyncMutexLock()
override suspend fun put(cache: T): Boolean = lock {
rootNode = Node(cache, rootNode)
true
}
override suspend fun get(): T? = lock {
val node = rootNode
rootNode = rootNode?.next
node?.value
}
private class Node<T>(var value: T? = null, var next: Node<T>? = null)
}

View File

@ -1,40 +0,0 @@
package cn.tursom.utils.pool
import cn.tursom.core.bytebuffer.HeapByteBuffer
import cn.tursom.core.datastruct.ArrayBitSet
import cn.tursom.core.pool.AsyncPool
import cn.tursom.utils.asynclock.AsyncMutexLock
import java.nio.ByteBuffer
@Suppress("MemberVisibilityCanBePrivate")
class AsyncMemoryPool(val blockSize: Int = 1024, val blockCount: Int = 16) : AsyncPool<ByteBuffer> {
private val memoryPool = ByteArray(blockSize * blockCount)
private val bitSet = ArrayBitSet(blockCount.toLong())
private val lock = AsyncMutexLock()
override suspend fun put(cache: ByteBuffer): Boolean {
if (cache.array() !== memoryPool) return false
val index = (cache.arrayOffset() / blockSize).toLong()
lock {
bitSet.down(index)
}
cache.asCharBuffer()
return true
}
override suspend fun get(): ByteBuffer? {
val index = lock {
val index = bitSet.firstDown()
if (index >= 0) bitSet.up(index)
index
}.toInt()
return if (index < 0 || index > blockCount) null
else HeapByteBuffer.wrap(memoryPool, blockSize * index, blockSize)
}
fun contain(buffer: ByteBuffer) = buffer.array() === memoryPool
}

View File

@ -1,146 +0,0 @@
package cn.tursom.web.netty
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import io.netty.buffer.ByteBuf
import java.io.OutputStream
import java.nio.ByteBuffer
class NettyAdvanceByteBuffer(val byteBuf: ByteBuf) : AdvanceByteBuffer {
override val hasArray: Boolean get() = byteBuf.hasArray()
override val readOnly: Boolean get() = byteBuf.isReadOnly
override val nioBuffer: ByteBuffer
get() = if (readMode) byteBuf.nioBuffer()
else byteBuf.nioBuffer(writePosition, limit)
override val bufferCount: Int get() = byteBuf.nioBufferCount()
override val nioBuffers: Array<out ByteBuffer> get() = byteBuf.nioBuffers()
override var writePosition: Int
get() = byteBuf.writerIndex()
set(value) {
byteBuf.writerIndex(value)
}
override var limit: Int
get() = byteBuf.capacity()
set(value) {
byteBuf.capacity(value)
}
override val capacity get() = byteBuf.maxCapacity()
override val array: ByteArray get() = byteBuf.array()
override val arrayOffset: Int get() = byteBuf.arrayOffset()
override var readPosition: Int
get() = byteBuf.readerIndex()
set(value) {
byteBuf.readerIndex(value)
}
override val readOffset: Int get() = byteBuf.arrayOffset() + byteBuf.readerIndex()
override val readableSize: Int
get() = byteBuf.readableBytes()
override val available: Int get() = readableSize
override val writeOffset: Int get() = writePosition
override val writeableSize: Int
get() = limit - writePosition
override val size: Int get() = capacity
override var readMode: Boolean = false
override fun readMode() {
readMode = true
}
override fun resumeWriteMode(usedSize: Int) {
readPosition += usedSize
readMode = false
}
override fun needReadSize(size: Int) {
if (size > limit) {
if (size < capacity) byteBuf.capacity(size)
else throw IndexOutOfBoundsException()
}
}
override fun clear() {
byteBuf.clear()
}
override fun reset() {
byteBuf.discardReadBytes()
}
override fun reset(outputStream: OutputStream) {
byteBuf.readBytes(outputStream, readableSize)
byteBuf.clear()
}
override fun get(): Byte = byteBuf.readByte()
override fun getChar(): Char = byteBuf.readChar()
override fun getShort(): Short = byteBuf.readShort()
override fun getInt(): Int = byteBuf.readInt()
override fun getLong(): Long = byteBuf.readLong()
override fun getFloat(): Float = byteBuf.readFloat()
override fun getDouble(): Double = byteBuf.readDouble()
override fun getBytes(size: Int): ByteArray {
val bytes = ByteArray(size)
byteBuf.readBytes(bytes)
return bytes
}
override fun getString(size: Int): String {
val str = byteBuf.toString(readPosition, size, Charsets.UTF_8)
readPosition += size
return str
}
override fun writeTo(buffer: ByteArray, bufferOffset: Int, size: Int): Int {
byteBuf.readBytes(buffer, bufferOffset, size)
return size
}
override fun writeTo(os: OutputStream): Int {
val size = readableSize
byteBuf.readBytes(os, size)
reset()
return size
}
override fun put(byte: Byte) {
byteBuf.writeByte(byte.toInt())
}
override fun put(char: Char) {
byteBuf.writeChar(char.toInt())
}
override fun put(short: Short) {
byteBuf.writeShort(short.toInt())
}
override fun put(int: Int) {
byteBuf.writeInt(int)
}
override fun put(long: Long) {
byteBuf.writeLong(long)
}
override fun put(float: Float) {
byteBuf.writeFloat(float)
}
override fun put(double: Double) {
byteBuf.writeDouble(double)
}
override fun put(str: String) {
byteBuf.writeCharSequence(str, Charsets.UTF_8)
}
override fun put(byteArray: ByteArray, startIndex: Int, endIndex: Int) {
byteBuf.writeBytes(byteArray, startIndex, endIndex - startIndex)
}
override fun toString(): String {
return "NettyAdvanceByteBuffer(byteBuf=$byteBuf, readMode=$readMode)"
}
}

View File

@ -0,0 +1,121 @@
package cn.tursom.web.netty
import cn.tursom.core.buffer.ByteBuffer
import io.netty.buffer.ByteBuf
import java.io.OutputStream
class NettyByteBuffer(val byteBuf: ByteBuf) : ByteBuffer {
override val hasArray: Boolean get() = byteBuf.hasArray()
override var writePosition: Int
get() = byteBuf.writerIndex()
set(value) {
byteBuf.writerIndex(value)
}
override val capacity get() = byteBuf.maxCapacity()
override val array: ByteArray get() = byteBuf.array()
override val arrayOffset: Int get() = byteBuf.arrayOffset()
override var readPosition: Int
get() = byteBuf.readerIndex()
set(value) {
byteBuf.readerIndex(value)
}
override val resized: Boolean get() = false
override fun readBuffer(): java.nio.ByteBuffer {
return byteBuf.internalNioBuffer(readPosition, readable)
}
override fun writeBuffer(): java.nio.ByteBuffer {
return byteBuf.internalNioBuffer(writePosition, writeable)
}
override val readOffset: Int get() = byteBuf.arrayOffset() + byteBuf.readerIndex()
override fun clear() {
byteBuf.clear()
}
override fun reset() {
byteBuf.discardReadBytes()
}
override fun slice(offset: Int, size: Int): ByteBuffer {
return NettyByteBuffer(byteBuf.slice(offset, size))
}
override fun resize(newSize: Int): Boolean {
return false
}
override fun get(): Byte = byteBuf.readByte()
override fun getChar(): Char = byteBuf.readChar()
override fun getShort(): Short = byteBuf.readShort()
override fun getInt(): Int = byteBuf.readInt()
override fun getLong(): Long = byteBuf.readLong()
override fun getFloat(): Float = byteBuf.readFloat()
override fun getDouble(): Double = byteBuf.readDouble()
override fun getBytes(size: Int): ByteArray {
val bytes = ByteArray(size)
byteBuf.readBytes(bytes)
return bytes
}
override fun getString(size: Int): String {
val str = byteBuf.toString(readPosition, size, Charsets.UTF_8)
readPosition += size
return str
}
override fun writeTo(buffer: ByteArray, bufferOffset: Int, size: Int): Int {
byteBuf.readBytes(buffer, bufferOffset, size)
return size
}
override fun writeTo(os: OutputStream): Int {
val size = readable
byteBuf.readBytes(os, size)
reset()
return size
}
override fun put(byte: Byte) {
byteBuf.writeByte(byte.toInt())
}
override fun put(char: Char) {
byteBuf.writeChar(char.toInt())
}
override fun put(short: Short) {
byteBuf.writeShort(short.toInt())
}
override fun put(int: Int) {
byteBuf.writeInt(int)
}
override fun put(long: Long) {
byteBuf.writeLong(long)
}
override fun put(float: Float) {
byteBuf.writeFloat(float)
}
override fun put(double: Double) {
byteBuf.writeDouble(double)
}
override fun put(str: String) {
byteBuf.writeCharSequence(str, Charsets.UTF_8)
}
override fun put(byteArray: ByteArray, startIndex: Int, endIndex: Int) {
byteBuf.writeBytes(byteArray, startIndex, endIndex - startIndex)
}
override fun toString(): String {
return "Nettyjava.nio.ByteBuffer(byteBuf=$byteBuf)"
}
}

View File

@ -1,39 +1,42 @@
package cn.tursom.web.netty
import cn.tursom.core.bytebuffer.AdvanceByteBuffer
import cn.tursom.core.buffer.ByteBuffer
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufAllocator
import io.netty.buffer.Unpooled
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.stream.ChunkedInput
class NettyChunkedByteBuffer(val bufList: List<AdvanceByteBuffer>) : ChunkedInput<ByteBuf> {
constructor(vararg bufList: AdvanceByteBuffer) : this(bufList.asList())
class NettyChunkedByteBuffer(private val bufList: List<ByteBuffer>) : ChunkedInput<ByteBuf> {
constructor(vararg bufList: ByteBuffer) : this(bufList.asList())
var iterator = bufList.iterator()
var progress: Long = 0
val length = run {
var len = 0L
bufList.forEach {
len += it.readableSize
}
len
}
private var next: ByteBuffer? = null
val iterator = bufList.iterator()
private var progress: Long = 0
private val length = run {
var len = 0L
bufList.forEach {
len += it.readable
}
len
}
override fun progress(): Long = progress
override fun length(): Long = length
override fun isEndOfInput(): Boolean = !iterator.hasNext()
override fun progress(): Long = progress
override fun length(): Long = length
override fun isEndOfInput(): Boolean = !iterator.hasNext()
override fun readChunk(ctx: ChannelHandlerContext?): ByteBuf = readChunk()
override fun readChunk(allocator: ByteBufAllocator?): ByteBuf = readChunk()
override fun readChunk(ctx: ChannelHandlerContext?): ByteBuf = readChunk()
override fun readChunk(allocator: ByteBufAllocator?): ByteBuf = readChunk()
private fun readChunk(): ByteBuf {
val next = iterator.next()
progress += next.readableSize
return if (next is NettyAdvanceByteBuffer) next.byteBuf
else Unpooled.wrappedBuffer(next.nioBuffer)
}
private fun readChunk(): ByteBuf {
this.next?.close()
val next = iterator.next()
this.next = next
progress += next.readable
return if (next is NettyByteBuffer) next.byteBuf
else Unpooled.wrappedBuffer(next.readBuffer())
}
override fun close() {}
override fun close() {}
}

Some files were not shown because too many files have changed in this diff Show More