main.shark.RandomAccessHprofReader.kt Maven / Gradle / Ivy
package shark
import okio.Buffer
import java.io.Closeable
import java.io.File
/**
* Reads records in a Hprof source, one at a time with a specific position and size.
* Call [openReaderFor] to obtain a new instance.
*/
class RandomAccessHprofReader private constructor(
private val source: RandomAccessSource,
hprofHeader: HprofHeader
) : Closeable {
private val buffer = Buffer()
private val reader = HprofRecordReader(hprofHeader, buffer)
/**
* Loads [recordSize] bytes at [recordPosition] into the buffer that backs [HprofRecordReader]
* then calls [withRecordReader] with that reader as a receiver. [withRecordReader] is expected
* to use the receiver reader to read one record of exactly [recordSize] bytes.
* @return the results from [withRecordReader]
*/
fun readRecord(
recordPosition: Long,
recordSize: Long,
withRecordReader: HprofRecordReader.() -> T
): T {
require(recordSize > 0L) {
"recordSize $recordSize must be > 0"
}
var mutablePos = recordPosition
var mutableByteCount = recordSize
while (mutableByteCount > 0L) {
val bytesRead = source.read(buffer, mutablePos, mutableByteCount)
check(bytesRead > 0) {
"Requested $mutableByteCount bytes after reading ${mutablePos - recordPosition}, got 0 bytes instead."
}
mutablePos += bytesRead
mutableByteCount -= bytesRead
}
return withRecordReader(reader).apply {
check(buffer.size() == 0L) {
"Buffer not fully consumed: ${buffer.size()} bytes left"
}
}
}
override fun close() {
source.close()
}
companion object {
fun openReaderFor(
hprofFile: File,
hprofHeader: HprofHeader = HprofHeader.parseHeaderOf(hprofFile)
): RandomAccessHprofReader {
val sourceProvider = FileSourceProvider(hprofFile)
return openReaderFor(sourceProvider, hprofHeader)
}
fun openReaderFor(
hprofSourceProvider: RandomAccessSourceProvider,
hprofHeader: HprofHeader = hprofSourceProvider.openRandomAccessSource()
.use { HprofHeader.parseHeaderOf(it.asStreamingSource()) }
): RandomAccessHprofReader {
return RandomAccessHprofReader(hprofSourceProvider.openRandomAccessSource(), hprofHeader)
}
}
}