All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jetbrains.exodus.io.FileDataReader.kt Maven / Gradle / Ivy

There is a newer version: 9.8.0.76914
Show newest version
/**
 * Copyright 2010 - 2022 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jetbrains.exodus.io

import jetbrains.exodus.ExodusException
import jetbrains.exodus.core.dataStructures.LongArrayList
import jetbrains.exodus.log.Log
import jetbrains.exodus.log.LogUtil
import mu.KLogging
import java.io.File
import java.io.IOException

class FileDataReader(val dir: File) : DataReader, KLogging() {

    companion object : KLogging()

    private var useNio = false
    private var log: Log? = null

    internal var usedWithWatcher = false

    override fun getBlocks(): Iterable {
        val files = LogUtil.listFileAddresses(dir)
        files.sort()
        return toBlocks(files)
    }

    override fun getBlocks(fromAddress: Long): Iterable {
        val files = LogUtil.listFileAddresses(fromAddress, dir)
        files.sort()
        return toBlocks(files)
    }


    override fun close() {
        try {
            SharedOpenFilesCache.getInstance().removeDirectory(dir)
            if (useNio) {
                SharedMappedFilesCache.getInstance().removeDirectory(dir)
            }
        } catch (e: IOException) {
            throw ExodusException("Can't close all files", e)
        }
    }

    fun setLog(log: Log) {
        this.log = log
    }

    override fun getLocation(): String {
        return dir.path
    }

    internal fun useNio(freePhysicalMemoryThreshold: Long) {
        useNio = true
        SharedMappedFilesCache.createInstance(freePhysicalMemoryThreshold)
    }

    private fun toBlocks(files: LongArrayList) =
            files.toArray().asSequence().map { address -> FileBlock(address, this) }.asIterable()

    class FileBlock(private val address: Long, private val reader: FileDataReader) :
            File(reader.dir, LogUtil.getLogFilename(address)), Block {

        override fun getAddress() = address

        override fun read(output: ByteArray, position: Long, offset: Int, count: Int): Int {
            try {
                val log = reader.log
                val immutable = log?.isImmutableFile(address) ?: !canWrite()
                val filesCache = SharedOpenFilesCache.getInstance()
                val file = if (immutable && !reader.usedWithWatcher) filesCache.getCachedFile(this) else filesCache.openFile(this)
                file.use { f ->
                    if (reader.useNio &&
                            /* only read-only (immutable) files can be mapped */ immutable) {
                        try {
                            SharedMappedFilesCache.getInstance().getFileBuffer(f).use { mappedBuffer ->
                                val buffer = mappedBuffer.buffer
                                buffer.position(position.toInt())
                                buffer.get(output, offset, count)
                                return count
                            }
                        } catch (t: Throwable) {
                            // if we failed to read mapped file, then try ordinary RandomAccessFile.read()
                            if (logger.isWarnEnabled) {
                                logger.warn("Failed to transfer bytes from memory mapped file", t)
                            }
                        }
                    }
                    f.seek(position)
                    return f.read(output, offset, count)
                }
            } catch (e: IOException) {
                throw ExodusException("Can't read file $absolutePath", e)
            }
        }

        override fun refresh() = this
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy