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

commonTest.maryk.rocksdb.AbstractComparatorTest.kt Maven / Gradle / Ivy

// Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
//  This source code is licensed under both the GPLv2 (found in the
//  COPYING file in the root directory) and Apache 2.0 License
//  (found in the LICENSE.Apache file in the root directory).

package maryk.rocksdb

import maryk.encodeToByteArray
import kotlin.random.Random
import kotlin.test.assertEquals
import kotlin.test.assertTrue

/** Abstract tests for both Comparator and DirectComparator */
abstract class AbstractComparatorTest {
    /**
     * Get a comparator which will expect Integer keys
     * and determine an ascending order
     *
     * @return An integer ascending order key comparator
     */
    abstract val ascendingIntKeyComparator: AbstractComparator

    /**
     * Test which stores random keys into the database
     * using an @see getAscendingIntKeyComparator
     * it then checks that these keys are read back in
     * ascending order
     *
     * @param db_path A path where we can store database
     * files temporarily
     *
     * @throws RocksDBException
     */
    fun testRoundtrip(db_path: String) {
        ascendingIntKeyComparator.use { comparator ->
            Options().apply {
                setCreateIfMissing(true)
                setComparator(comparator)
            }.use { opt ->
                // store 10,000 random integer keys
                val iterations = 10000
                openRocksDB(opt, db_path).use { db ->
                    val value = "value".encodeToByteArray()
                    var i = 0
                    while (i < iterations) {
                        val key = Random.nextBytes(4)
                        // does key already exist (avoid duplicates)
                        if (i > 0 && db[key] != null) {
                            i-- // generate a different key
                        } else {
                            db.put(key, value)
                        }
                        i++
                    }
                }

                // re-open db and read from start to end
                // integer keys should be in ascending
                // order as defined by SimpleIntComparator
                openRocksDB(opt, db_path).use { db ->
                    db.newIterator().use {
                        var lastKey = Int.MIN_VALUE
                        var count = 0
                        it.seekToFirst()
                        while (it.isValid()) {
                            val thisKey = byteToInt(it.key())
                            assertTrue(thisKey > lastKey)
                            lastKey = thisKey
                            count++
                            it.next()
                        }
                        assertEquals(iterations, count)
                    }
                }
            }
        }
    }

    /**
     * Test which stores random keys into a column family
     * in the database
     * using an @see getAscendingIntKeyComparator
     * it then checks that these keys are read back in
     * ascending order
     *
     * @param db_path A path where we can store database
     * files temporarily
     */
    fun testRoundtripCf(db_path: String) {
        ascendingIntKeyComparator.use { comparator ->
            val cfDescriptors = listOf(
                ColumnFamilyDescriptor(defaultColumnFamily),
                ColumnFamilyDescriptor(
                    "new_cf".encodeToByteArray(),
                    ColumnFamilyOptions().setComparator(comparator)
                )
            )

            val cfHandles = mutableListOf()

            DBOptions().apply {
                setCreateIfMissing(true)
                setCreateMissingColumnFamilies(true)
            }.use { opt ->
                // store 10,000 random integer keys
                val iterations = 10000

                openRocksDB(
                    opt, db_path,
                    cfDescriptors,
                    cfHandles
                ).use { db ->
                    try {
                        assertEquals(2, cfDescriptors.size)
                        assertEquals(2, cfHandles.size)

                        val value = "value".encodeToByteArray()
                        var i = 0
                        while (i < iterations) {
                            val key = Random.nextBytes(4)
                            if (i > 0 && db.get(cfHandles[1], key) != null) {
                                // does key already exist (avoid duplicates)
                                i-- // generate a different key
                            } else {
                                db.put(cfHandles[1], key, value)
                            }
                            i++
                        }
                    } finally {
                        for (handle in cfHandles) {
                            handle.close()
                        }
                    }
                    cfHandles.clear()
                }

                // re-open db and read from start to end
                // integer keys should be in ascending
                // order as defined by SimpleIntComparator
                openRocksDB(
                    opt, db_path,
                    cfDescriptors, cfHandles
                ).use { db ->
                    db.newIterator(cfHandles[1]).use {
                        try {
                            assertEquals(2, cfDescriptors.size)
                            assertEquals(2, cfHandles.size)

                            it.seekToFirst()
                            var lastKey = Int.MIN_VALUE
                            var count = 0
                            it.seekToFirst()
                            while (it.isValid()) {
                                val thisKey = byteToInt(it.key())
                                assertTrue(thisKey > lastKey)
                                lastKey = thisKey
                                count++
                                it.next()
                            }

                            assertEquals(iterations, count)
                        } finally {
                            for (handle in cfHandles) {
                                handle.close()
                            }
                        }
                        cfHandles.clear()
                    }
                }
            }
        }
    }

    /**
     * Compares integer keys
     * so that they are in ascending order
     *
     * @param a 4-bytes representing an integer key
     * @param b 4-bytes representing an integer key
     *
     * @return negative if a < b, 0 if a == b, positive otherwise
     */
    protected fun compareIntKeys(a: ByteArray, b: ByteArray): Int {
        val iA = byteToInt(a)
        val iB = byteToInt(b)

        // protect against int key calculation overflow
        val diff = iA.toDouble() - iB
        return when {
            diff < Int.MIN_VALUE -> Int.MIN_VALUE
            diff > Int.MAX_VALUE -> Int.MAX_VALUE
            else -> diff.toInt()
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy