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

ai.platon.pulsar.ql.h2.H2Db.kt Maven / Gradle / Ivy

The newest version!
package ai.platon.pulsar.ql.h2

import ai.platon.pulsar.common.AppContext
import ai.platon.pulsar.common.AppPaths
import org.apache.commons.lang3.SystemUtils
import org.h2.store.FileLister
import org.h2.tools.DeleteDbFiles
import java.sql.Connection
import java.sql.DriverManager
import java.util.*
import kotlin.math.abs

/**
 * A wrapper for h2 database
 */
class H2Db(val conf: H2DbConfig = H2DbConfig()) {
    companion object {
        val TEST_DB_CONFIG = H2DbConfig().apply {
            baseDir = AppPaths.TEST_DIR.resolve("h2")
        }
        val TEST_DB = H2Db(TEST_DB_CONFIG)
    }

    fun generateTempDbName(): String {
        return "" + System.currentTimeMillis() + "_" + abs(Random().nextInt());
    }

    /**
     * Open a database with a random named connection in admin mode.
     * The default username and password is used.
     *
     * @return the connection
     */
    fun getRandomConnection() = getConnection(generateTempDbName())

    /**
     * Open a database connection in admin mode. The default username and
     * password is used.
     *
     * @param name the database name
     * @return the connection
     */
    fun getConnection(name: String) = getConnection0(buildURL(name, true), conf.user, conf.password)

    /**
     * Open a database connection.
     *
     * @param name the database name
     * @param user the username to use
     * @param password the password to use
     * @return the connection
     */
    fun getConnection(name: String, user: String, password: String) =
            getConnection0(buildURL(name, false), user, password)

    /**
     * Get the password to use to log in for the given user password. The file
     * password is added if required.
     *
     * @param userPassword the password of this user
     * @return the login password
     */
    fun getPassword(userPassword: String): String {
        return if (conf.cipher == null)
            userPassword
        else
            "${conf.filePassword} $userPassword"
    }

    /**
     * Get the base directory for tests.
     * If a special file system is used, the prefix is prepended.
     *
     * @return the directory, possibly including file system prefix
     */
    fun buildBaseDir(): String {
        var dir = conf.baseDir.toString()
        if (conf.reopen) {
            dir = "rec:memFS:$dir"
        }
        if (conf.splitFileSystem) {
            dir = "split:16:$dir"
        }
        // return "split:nioMapped:" + baseDir;
        return dir
    }

    /**
     * Get the database URL for the given database name using the current
     * configuration options.
     *
     * @param name the database name
     * @param admin true if the current user is an admin
     * @return the database URL
     */
    fun buildURL(name: String, admin: Boolean): String {
        var name0 = name
        var url: String
        if (name0.startsWith("jdbc:")) {
            name0 = if (conf.mvStore) {
                addOption(name0, "MV_STORE", "true")
            } else {
                addOption(name0, "MV_STORE", "false")
            }
            return name0
        }
        if (admin) { // name = addOption(name, "RETENTION_TIME", "10");
            // name = addOption(name, "WRITE_DELAY", "10");
        }
        val idx = name0.indexOf(':')
        if (idx == -1 && conf.memory) {
            name0 = "mem:$name0"
        } else {
            if (idx < 0 || idx > 10) { // index > 10 if in options
                name0 = "${conf.baseDir}/$name0"
            }
        }
        url = if (conf.networked) {
            if (conf.ssl) {
                "ssl://localhost:" + conf.port + "/" + name0
            } else {
                "tcp://localhost:" + conf.port + "/" + name0
            }
        } else {
            name0
        }
        if (conf.mvStore) {
            url = addOption(url, "MV_STORE", "true")
            url = addOption(url, "MAX_COMPACT_TIME", "0") // to speed up tests
        } else {
            url = addOption(url, "MV_STORE", "false")
        }
        if (!conf.memory) {
            if (conf.smallLog && admin) {
                url = addOption(url, "MAX_LOG_SIZE", "1")
            }
        }
        if (conf.traceSystemOut) {
            url = addOption(url, "TRACE_LEVEL_SYSTEM_OUT", "2")
        }
        if (conf.traceLevelFile > 0 && admin) {
            url = addOption(url, "TRACE_LEVEL_FILE", "" + conf.traceLevelFile)
            url = addOption(url, "TRACE_MAX_FILE_SIZE", "8")
        }
        url = addOption(url, "LOG", "1")
        if (conf.throttleDefault > 0) {
            url = addOption(url, "THROTTLE", "" + conf.throttleDefault)
        } else if (conf.throttle > 0) {
            url = addOption(url, "THROTTLE", "" + conf.throttle)
        }
        url = addOption(url, "LOCK_TIMEOUT", "" + conf.lockTimeout)
        if (conf.diskUndo && admin) {
            url = addOption(url, "MAX_MEMORY_UNDO", "3")
        }
        if (conf.big && admin) { // force operations to disk
            url = addOption(url, "MAX_OPERATION_MEMORY", "1")
        }
        if (conf.lazy) {
            url = addOption(url, "LAZY_QUERY_EXECUTION", "1")
        }
//        if (conf.cacheType != null && admin) {
//            url = addOption(url, "CACHE_TYPE", conf.cacheType)
//        }
        if (conf.diskResult && admin) {
            url = addOption(url, "MAX_MEMORY_ROWS", "100")
            url = addOption(url, "CACHE_SIZE", "0")
        }
//        if (conf.cipher != null) {
//            url = addOption(url, "CIPHER", conf.cipher)
//        }
        if (conf.defrag) {
            url = addOption(url, "DEFRAG_ALWAYS", "TRUE")
        }
//        if (conf.collation != null) {
//            url = addOption(url, "COLLATION", conf.collation)
//        }
        return "jdbc:h2:$url"
    }

    /**
     * Delete all database files for this database.
     *
     * @param name the database name
     */
    fun deleteDb(name: String) = deleteDb(buildBaseDir(), name)

    /**
     * Delete all database files for a database.
     *
     * @param dir the directory where the database files are located
     * @param name the database name
     */
    fun deleteDb(dir: String, name: String) {
        DeleteDbFiles.execute(dir, name, true)
         val list = FileLister.getDatabaseFiles(conf.baseDir.toString(), name, true);
         if (list.isNotEmpty()) {
             System.err.println("Not deleted: $list")
         }
    }

    private fun addOption(url: String, option: String, value: String): String {
        var u = url
        if (u.indexOf(";$option=") < 0) {
            u += ";$option=$value"
        }
        return u
    }

    private fun getConnection0(url: String, user: String, password: String): Connection {
        // println("Open H2 Connection: $url")
        org.h2.Driver.load()
        return DriverManager.getConnection(url, user, password)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy