<commit_before>/*
 * Komunumo – Open Source Community Manager
 * Copyright (C) 2017 Java User Group Switzerland
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package ch.komunumo.server

import mu.KotlinLogging
import org.mapdb.DB
import org.mapdb.DBMaker
import org.mapdb.Serializer
import java.io.Serializable
import java.nio.file.Paths
import java.util.concurrent.ConcurrentMap
import kotlin.reflect.KClass

object PersistenceManager {

    private val db: DB
    private val logger = KotlinLogging.logger {}

    init {
        val homeDir = System.getProperty("user.home")
        val dbPath = Paths.get(homeDir, ".komunumo", "komunumo.db")
        val dbFile = dbPath.toFile()
        logger.info { "Using persistence store: $dbFile" }
        db = DBMaker.fileDB(dbFile)
                .fileMmapEnableIfSupported()
                .transactionEnable()
                .closeOnJvmShutdown()
                .make()
    }

    @Suppress("UNCHECKED_CAST") // TODO talk to the mapDB developers for a better solution
    fun <T : Serializable> createPersistedMap(name: String, clazz: KClass<out T>): ConcurrentMap<String, T> {
        return db.hashMap(name)
                .keySerializer(Serializer.STRING)
                .valueSerializer(Serializer.JAVA)
                .createOrOpen() as ConcurrentMap<String, T>
    }

}<commit_msg>:bug: Fixing bug loosing data on restart #3<commit_after>/*
 * Komunumo – Open Source Community Manager
 * Copyright (C) 2017 Java User Group Switzerland
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package ch.komunumo.server

import mu.KotlinLogging
import org.mapdb.DB
import org.mapdb.DBMaker
import org.mapdb.HTreeMap
import org.mapdb.Serializer
import java.io.Serializable
import java.nio.file.Paths
import kotlin.reflect.KClass

object PersistenceManager {

    private val db: DB
    private val logger = KotlinLogging.logger {}

    init {
        val homeDir = System.getProperty("user.home")
        val dbPath = Paths.get(homeDir, ".komunumo", "komunumo.db")
        val dbFile = dbPath.toFile()
        logger.info { "Using persistence store: $dbFile" }
        db = DBMaker.fileDB(dbFile)
                .fileMmapEnableIfSupported()
                .transactionEnable()
                .closeOnJvmShutdown()
                .make()
    }

    @Suppress("UNCHECKED_CAST") // TODO talk to the mapDB developers for a better solution
    fun <T : Serializable> createPersistedMap(name: String, clazz: KClass<out T>): MutableMap<String, T> {
        val hTreeMap = db.hashMap(name)
                .keySerializer(Serializer.STRING)
                .valueSerializer(Serializer.JAVA)
                .createOrOpen() as HTreeMap<String, T>
        val autoCommitMap = AutoCommitMap<String, T>(db, hTreeMap)
        return autoCommitMap
    }

}

private class AutoCommitMap<K, V>(val db: DB, val map: HTreeMap<K, V>) : MutableMap<K, V> {

    override val size: Int
        get() = map.size

    @Suppress("UNCHECKED_CAST")
    override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
        get() = map.entries as MutableSet<MutableMap.MutableEntry<K, V>>

    override val keys: MutableSet<K>
        get() = map.keys

    @Suppress("UNCHECKED_CAST")
    override val values: MutableCollection<V>
        get() = map.values as MutableCollection<V>

    override fun containsKey(key: K): Boolean {
        return map.containsKey(key)
    }

    override fun containsValue(value: V): Boolean {
        return map.containsValue(value)
    }

    override fun get(key: K): V? {
        return map.get(key)
    }

    override fun isEmpty(): Boolean {
        return map.isEmpty()
    }

    override fun clear() {
        map.clear()
        db.commit()
    }

    override fun put(key: K, value: V): V? {
        val oldValue = map.put(key, value)
        db.commit()
        return oldValue
    }

    override fun putAll(from: Map<out K, V>) {
        map.putAll(from)
        db.commit()
    }

    override fun remove(key: K): V? {
        val oldValue = map.remove(key)
        db.commit()
        return oldValue
    }

}
{'fraction_non_alphanumeric': 0.09186351706036745, 'fraction_numerical': 0.0020622422197225346, 'mean_word_length': 2.775654635527247, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7246507', 'n_tokens_mistral': 1567, 'n_tokens_neox': 1523, 'n_words': 516}