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

org.mapdb.BTreeMap.kt Maven / Gradle / Ivy

Go to download

MapDB provides concurrent Maps, Sets and Queues backed by disk storage or off-heap memory. It is a fast, scalable and easy to use embedded Java database.

There is a newer version: 3.1.0
Show newest version
package org.mapdb

import org.eclipse.collections.api.list.primitive.MutableLongList
import org.eclipse.collections.impl.list.mutable.primitive.LongArrayList
import org.eclipse.collections.impl.set.mutable.primitive.LongHashSet
import org.eclipse.collections.impl.stack.mutable.primitive.LongArrayStack
import org.mapdb.BTreeMapJava.*
import org.mapdb.serializer.GroupSerializer
import java.io.Closeable
import java.io.ObjectStreamException
import java.io.PrintStream
import java.io.Serializable
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentNavigableMap
import java.util.concurrent.ConcurrentSkipListMap
import java.util.concurrent.locks.LockSupport
import java.util.function.BiConsumer

/**
 * A scalable concurrent {@link ConcurrentNavigableMap} implementation.
 * The map is sorted according to the {@linkplain Comparable natural
 * ordering} of its keys, or by a {@link Comparator} provided at map
 * creation time.
 *
 * Insertion, removal,
 * update, and access operations safely execute concurrently by
 * multiple threads.  Iterators are weakly consistent, returning
 * elements reflecting the state of the map at some point at or since
 * the creation of the iterator.  They do not throw {@link
 * ConcurrentModificationException}, and may proceed concurrently with
 * other operations. Ascending key ordered views and their iterators
 * are faster than descending ones.
 *
 *
 * By default BTreeMap does not track its size and {@code size()} traverses collection to count its entries.
 * There is option to enable counter, in that case {@code size()} returns instantly
 *
 * Additionally, the bulk operations putAll, equals, and
 * clear are not guaranteed to be performed
 * atomically. For example, an iterator operating concurrently with a
 * putAll operation might view only some of the added
 * elements. NOTE: there is an optional
 *
 * This class and its views and iterators implement all of the
 * optional methods of the {@link Map} and {@link Iterator}
 * interfaces. Like most other concurrent collections, this class does
 * not permit the use of null keys or values because some
 * null return values cannot be reliably distinguished from the absence of
 *
 * Theoretical design of BTreeMap is based on 1986 paper
 * 
 * Concurrent operations on B∗-trees with overtaking
 * written by Yehoshua Sagiv.
 * More practical aspects of BTreeMap implementation are based on
 * demo application from Thomas Dinsdale-Young.
 * Also more work from Thomas: A Simple Abstraction for Complex Concurrent Indexes
 *
 * B-Linked-Tree used here does not require locking for read.
 * Updates and inserts locks only one, two or three nodes.
 * 

* * This B-Linked-Tree structure does not support removal well, entry deletion does not collapse tree nodes. Massive * deletion causes empty nodes and performance lost. There is workaround in form of compaction process, but it is not * implemented yet. *

* * @author Jan Kotek * @author some parts by Doug Lea and JSR-166 group */ //TODo counted btrees class BTreeMap( override val keySerializer:GroupSerializer, override val valueSerializer:GroupSerializer, val rootRecidRecid:Long, val store:Store, val valueInline:Boolean, val maxNodeSize:Int, val comparator:Comparator, override val isThreadSafe:Boolean, val counterRecid:Long, override val hasValues:Boolean, private val modificationListeners: Array>? ):Verifiable, Closeable, Serializable, ConcurrencyAware, ConcurrentNavigableMap, ConcurrentNavigableMapExtra { companion object { fun make( keySerializer: GroupSerializer = Serializer.ELSA as GroupSerializer, valueSerializer: GroupSerializer = Serializer.ELSA as GroupSerializer, store: Store = StoreTrivial(), valueInline: Boolean = true, //insert recid of new empty node rootRecidRecid: Long = putEmptyRoot(store, keySerializer, if(valueInline) valueSerializer else Serializer.RECID), maxNodeSize: Int = CC.BTREEMAP_MAX_NODE_SIZE , comparator: Comparator = keySerializer, isThreadSafe:Boolean = true, counterRecid:Long=0L, hasValues:Boolean = true, modificationListeners: Array>? = null ) = BTreeMap( keySerializer = keySerializer, valueSerializer = valueSerializer, store = store, valueInline = valueInline, rootRecidRecid = rootRecidRecid, maxNodeSize = maxNodeSize, comparator = comparator, isThreadSafe = isThreadSafe, counterRecid = counterRecid, hasValues = hasValues, modificationListeners = modificationListeners ) internal fun putEmptyRoot(store: Store, keySerializer: GroupSerializer, valueSerializer: GroupSerializer): Long { return store.put( store.put( Node(LEFT + RIGHT, 0L, keySerializer.valueArrayEmpty(), valueSerializer.valueArrayEmpty()), NodeSerializer(keySerializer, keySerializer, valueSerializer)), Serializer.RECID) } internal val NO_VAL_SERIALIZER = object: GroupSerializer{ override fun valueArrayCopyOfRange(vals: Any?, from: Int, to: Int): Int? { return to-from; } override fun valueArrayDeleteValue(vals: Any?, pos: Int): Int? { return vals as Int-1 } override fun valueArrayDeserialize(`in`: DataInput2?, size: Int): Int? { return size } override fun valueArrayEmpty(): Int? { return 0 } override fun valueArrayFromArray(objects: Array?): Int? { throw IllegalAccessError() } override fun valueArrayGet(vals: Any?, pos: Int): Boolean? { return java.lang.Boolean.TRUE } override fun valueArrayPut(vals: Any?, pos: Int, newValue: Boolean?): Int? { return vals as Int + 1 } override fun valueArraySearch(keys: Any?, key: Boolean?): Int { throw IllegalAccessError() } override fun valueArraySearch(keys: Any?, key: Boolean?, comparator: Comparator<*>?): Int { throw IllegalAccessError() } override fun valueArraySerialize(out: DataOutput2?, vals: Any?) { } override fun valueArraySize(vals: Any?): Int { return vals as Int } override fun valueArrayUpdateVal(vals: Any?, pos: Int, newValue: Boolean?): Int? { return vals as Int } override fun deserialize(input: DataInput2, available: Int): Boolean? { throw IllegalAccessError(); } override fun serialize(out: DataOutput2, value: Boolean) { throw IllegalAccessError(); } override fun isTrusted(): Boolean { return true } } } init{ if(BTreeMap.NO_VAL_SERIALIZER==valueSerializer && hasValues) throw IllegalArgumentException("wrong value serializer") if(BTreeMap.NO_VAL_SERIALIZER!=valueSerializer && !hasValues) throw IllegalArgumentException("wrong value serializer") if(maxNodeSize<4) throw IllegalArgumentException("maxNodeSize too small") } private val hasBinaryStore = store is StoreBinary protected val valueNodeSerializer = (if(valueInline) this.valueSerializer else Serializer.RECID) as GroupSerializer protected val nodeSerializer = NodeSerializer(this.keySerializer, this.comparator, this.valueNodeSerializer); protected val rootRecid: Long get() = store.get(rootRecidRecid, Serializer.RECID) ?: throw DBException.DataCorruption("Root Recid not found"); /** recids of left-most nodes in tree */ protected val leftEdges: MutableLongList = loadLeftEdges() private fun loadLeftEdges(): MutableLongList { val ret = LongArrayList() var recid = rootRecid while (true) { val node = getNode(recid) if (CC.ASSERT && recid <= 0L) throw AssertionError() ret.add(recid) if (node.isDir.not()) break recid = node.children[0] } return ret.toReversed().asSynchronized() } protected val locks = ConcurrentHashMap() override operator fun get(key: K?): V? { if (key == null) throw NullPointerException() return if (hasBinaryStore) getBinary(key) else getNonBinary(key) } private fun getBinary(key: K): V? { val binary = store as StoreBinary var current = rootRecid val binaryGet = BinaryGet(keySerializer, valueNodeSerializer, comparator, key) do { current = binary.getBinaryLong(current, binaryGet) } while (current != -1L) return valueExpand(binaryGet.value) } protected fun listenerNotify(key:K, oldValue:V?, newValue: V?, triggered:Boolean){ if(modificationListeners!=null) for(l in modificationListeners) l.modify(key, oldValue, newValue, triggered) } protected fun valueExpand(v:Any?):V? { return ( if(v==null) null else if(valueInline) v else store.get(v as Long, valueSerializer) ) as V? } private fun getNonBinary(key: K?): V? { var current = rootRecid var A = getNode(current) //dive into bottom while (A.isDir) { current = findChild(keySerializer, A, comparator, key) A = getNode(current) } //follow link until necessary var ret = leafGet(A, comparator, key, keySerializer, valueNodeSerializer) while (LINK == ret) { current = A.link; A = getNode(current) ret = leafGet(A, comparator, key, keySerializer, valueNodeSerializer) } return valueExpand(ret); } override fun put(key: K?, value: V?): V? { if (key == null || value == null) throw NullPointerException() return put2(key, value, false) } private fun isLinkValue(pos:Int, A:Node):Boolean{ // TODO this needs more investigation, what if lastKeyIsDouble and search jumped there? val pos = pos - 1 + A.intLeftEdge(); return (!A.isLastKeyDouble && pos >= valueNodeSerializer.valueArraySize(A.values)) } protected fun put2(key: K, value: V, onlyIfAbsent: Boolean): V? { if (key == null || value == null) throw NullPointerException() try { var v = key!! var completed = false val stack = LongArrayStack() val rootRecid = rootRecid var current = rootRecid var A = getNode(current) while (A.isDir) { var t = current current = findChild(keySerializer, A, comparator, v) if (current != A.link) { stack.push(t) } A = getNode(current) } var level = 0 var p = 0L do { //TODO loop bellow follows link, leaf is already locked, only need to follow link is to handle inconsistencies after crash leafLink@ while (true) { lock(current) A = getNode(current) //follow link, until key is higher than highest key in node if (!A.isRightEdge && comparator.compare(v, A.highKey(keySerializer) as K) > 0) { //TODO PERF optimize //key is greater, load next link unlock(current) current = A.link continue@leafLink } break@leafLink } //current node is locked, and its highest value is higher/equal to key var pos = keySerializer.valueArraySearch(A.keys, v, comparator) if (pos >= 0) { if(A.isDir) { throw AssertionError(key); } if(!isLinkValue(pos, A)) { //entry exist in current node, so just update pos = pos - 1 + A.intLeftEdge(); //key exist in node, just update val oldValueRecid = valueNodeSerializer.valueArrayGet(A.values, pos) val oldValueExpand = valueExpand(oldValueRecid) //update only if not exist, return if (!onlyIfAbsent) { if (valueInline) { val values = valueNodeSerializer.valueArrayUpdateVal(A.values, pos, value) var flags = A.flags.toInt(); A = Node(flags, A.link, A.keys, values) store.update(current, A, nodeSerializer) } else { //update external value store.update(oldValueRecid as Long, value, valueSerializer) } listenerNotify(key, oldValueExpand, value, false) } unlock(current) return oldValueExpand }else{ //is linked key, will set lastKeyDouble flag, keys are unmodified and values have new value if(A.isLastKeyDouble) throw AssertionError() val flags = A.flags + BTreeMapJava.LAST_KEY_DOUBLE val value2 = if(valueInline) value else store.put(value, valueSerializer) pos = pos - 1 + A.intLeftEdge() val values = valueNodeSerializer.valueArrayPut(A.values, pos, value2) A = Node(flags, A.link, A.keys, values) store.update(current, A, nodeSerializer) listenerNotify(key, null, value, false) unlock(current) return null } } //normalise pos pos = if(pos>0) pos - 1 + A.intLeftEdge(); else -pos - 1 //key does not exist, node must be expanded val isRoot = A.isLeftEdge && A.isRightEdge A = if (A.isDir) { copyAddKeyDir(A, pos, v, p) } else { counterIncrement(1) listenerNotify(key, null, value, false) copyAddKeyLeaf(A, pos, v, value) } val keysSize = keySerializer.valueArraySize(A.keys) + A.intLastKeyTwice() if (keysSize < maxNodeSize) { //it is safe to insert without spliting store.update(current, A, nodeSerializer) unlock(current) return null } //node is not safe it requires split val splitPos = keysSize / 2 val B = copySplitRight(A, splitPos) val q = store.put(B, nodeSerializer) A = copySplitLeft(A, splitPos, q) store.update(current, A, nodeSerializer) if (!isRoot) { //is not root unlock(current) p = q v = A.highKey(keySerializer) as K // if(CC.ASSERT && COMPARATOR.compare(v, key)<0) // throw AssertionError() level++ current = if (stack.isEmpty.not()) { stack.pop() } else { leftEdgeGetLevel(level) } } else { //is root val R = Node( DIR + LEFT + RIGHT, 0L, keySerializer.valueArrayFromArray(arrayOf(A.highKey(keySerializer) as Any?)), longArrayOf(current, q) ) unlock(current) lock(rootRecidRecid) val newRootRecid = store.put(R, nodeSerializer) store.update(rootRecidRecid, newRootRecid, Serializer.RECID) leftEdges.add(newRootRecid) unlock(rootRecidRecid) return null; } } while (!completed) return null } catch(e: Throwable) { unlockAllCurrentThread() throw e } finally { if (CC.ASSERT) assertCurrentThreadUnlocked() } } private fun leftEdgeGetLevel(level: Int): Long { //TODO this is potencially infinitive loop if other thread fails before updating left edges //pointer to left most node at level while(true) { //there is a race condition, other node might have updated root, but leftEdges were not updated yet try { return leftEdges.get(level) }catch(e:IndexOutOfBoundsException){ //wait until the other node updates the level LockSupport.parkNanos(100) } } } override fun remove(key: K?): V? { if (key == null) throw NullPointerException() return removeOrReplace(key, null, null) } protected fun removeOrReplace(key: K, expectedOldValue: V?, replaceWithValue: V?): V? { if (key == null) throw NullPointerException() try { val v = key val rootRecid = rootRecid var current = rootRecid var A = getNode(current) while (A.isDir) { current = findChild(keySerializer, A, comparator, v) A = getNode(current) } //TODO loop bellow follows link, leaf is already locked, only need to follow link is to handle inconsistencies after crash leafLink@ while (true) { lock(current) A = getNode(current) //follow link, until key is higher than highest key in node if (!A.isRightEdge && comparator.compare(v, A.highKey(keySerializer) as K) > 0) { //key is greater, load next link unlock(current) current = A.link continue@leafLink } break@leafLink } //current node is locked, and its highest value is higher/equal to key val pos = keySerializer.valueArraySearch(A.keys, v, comparator) var oldValueRecid:Any? = null var oldValueExpanded:V? = null val keysSize = keySerializer.valueArraySize(A.keys); if (pos >= 1 - A.intLeftEdge() && pos < keysSize - 1 + A.intRightEdge() + A.intLastKeyTwice()) { val valuePos = pos - 1 + A.intLeftEdge(); //key exist in node, just update oldValueRecid = valueNodeSerializer.valueArrayGet(A.values, valuePos) oldValueExpanded = valueExpand(oldValueRecid) if(oldValueExpanded == null) { // this should not happen, since node is already locked throw AssertionError() } var keys = A.keys var flags = A.flags.toInt() if (expectedOldValue == null || (oldValueExpanded!=null && valueSerializer.equals(expectedOldValue!!, oldValueExpanded))) { val values = if (replaceWithValue == null) { //remove if (A.isLastKeyDouble && pos == keysSize - 1) { //last value is twice in node, but should be removed from here // instead of removing key, just unset flag flags -= LAST_KEY_DOUBLE } else { keys = keySerializer.valueArrayDeleteValue(A.keys, pos + 1) } counterIncrement(-1) if(!valueInline) store.update(oldValueRecid as Long, replaceWithValue, valueSerializer) valueNodeSerializer.valueArrayDeleteValue(A.values, valuePos + 1) } else if(valueInline){ valueNodeSerializer.valueArrayUpdateVal(A.values, valuePos, replaceWithValue) } else{ //update value without modifying original node, since its external store.update(oldValueRecid as Long, replaceWithValue, valueSerializer) null } if(values!=null) { A = Node(flags, A.link, keys, values) store.update(current, A, nodeSerializer) } listenerNotify(key, oldValueExpanded, replaceWithValue, false) }else{ //was not updated, so do not return anything oldValueExpanded = null } } unlock(current) return oldValueExpanded } catch(e: Throwable) { unlockAllCurrentThread() throw e } finally { if (CC.ASSERT) assertCurrentThreadUnlocked() } } private fun copySplitLeft(a: Node, splitPos: Int, link: Long): Node { var flags = a.intDir() * DIR + a.intLeftEdge() * LEFT + LAST_KEY_DOUBLE * (1 - a.intDir()) var keys = keySerializer.valueArrayCopyOfRange(a.keys, 0, splitPos) // if(!a.isDir) { // val keysSize = keySerializer.valueArraySize(keys) // val oneBeforeLast = keySerializer.valueArrayGet(keys, keysSize-2) // keys = keySerializer.valueArrayUpdateVal(keys, keysSize-1, oneBeforeLast) // } val valSplitPos = splitPos - 1 + a.intLeftEdge(); val values = if (a.isDir) { val c = a.values as LongArray Arrays.copyOfRange(c, 0, valSplitPos) } else { valueNodeSerializer.valueArrayCopyOfRange(a.values, 0, valSplitPos) } return Node(flags, link, keys, values) } private fun copySplitRight(a: Node, splitPos: Int): Node { val flags = a.intDir() * DIR + a.intRightEdge() * RIGHT + a.intLastKeyTwice() * LAST_KEY_DOUBLE val keys = keySerializer.valueArrayCopyOfRange(a.keys, splitPos - 1, keySerializer.valueArraySize(a.keys)) val valSplitPos = splitPos - 1 + a.intLeftEdge(); val values = if (a.isDir) { val c = a.values as LongArray Arrays.copyOfRange(c, valSplitPos, c.size) } else { val size = valueNodeSerializer.valueArraySize(a.values) valueNodeSerializer.valueArrayCopyOfRange(a.values, valSplitPos, size) } return Node(flags, a.link, keys, values) } private fun copyAddKeyLeaf(a: Node, insertPos: Int, key: K, value: V): Node { if (CC.ASSERT && a.isDir) throw AssertionError() val keysLen = keySerializer.valueArraySize(a.keys) var flags = a.flags.toInt() val keys = if(!a.isLastKeyDouble && keysLen!=0 && insertPos>=keysLen-2 && comparator.compare(key, a.highKey(keySerializer))==0){ //TODO PERF this comparation can be optimized away //last key is duplicated, no need to clone keys, just set duplication flag flags += BTreeMapJava.LAST_KEY_DOUBLE a.keys }else{ keySerializer.valueArrayPut(a.keys, insertPos, key) } val valuesInsertPos = if(valueNodeSerializer.valueArraySize(a.values)==0) 0 else insertPos - 1 + a.intLeftEdge(); val valueToInsert = if(valueInline) value else store.put(value, valueSerializer) val values = valueNodeSerializer.valueArrayPut(a.values, valuesInsertPos, valueToInsert) return Node(flags, a.link, keys, values) } private fun copyAddKeyDir(a: Node, insertPos: Int, key: K, newChild: Long): Node { if (CC.ASSERT && a.isDir.not()) throw AssertionError() val keys = keySerializer.valueArrayPut(a.keys, insertPos, key) val values = arrayPut(a.values as LongArray, insertPos + a.intLeftEdge(), newChild) return Node(a.flags.toInt(), a.link, keys, values) } fun lock(nodeRecid: Long) { if(!isThreadSafe) return val value = Thread.currentThread().id //try to lock, but only if current node is not empty while (locks.putIfAbsent(nodeRecid, value) != null) LockSupport.parkNanos(10) } fun unlock(nodeRecid: Long) { if(!isThreadSafe) return val v = locks.remove(nodeRecid) if (v == null || v != Thread.currentThread().id) throw AssertionError("Unlocked wrong thread"); } fun unlockAllCurrentThread() { if(!isThreadSafe) return val id = Thread.currentThread().id val iter = locks.iterator() while (iter.hasNext()) { val e = iter.next() if (e.value == id) { iter.remove() } } } fun assertCurrentThreadUnlocked() { if(!isThreadSafe) return val id = Thread.currentThread().id val iter = locks.iterator() while (iter.hasNext()) { val e = iter.next() if (e.value == id) { throw AssertionError("Node is locked: " + e.key) } } } override fun close() { store.close() } override fun verify() { fun verifyRecur(node: Node, left: Boolean, right: Boolean, knownNodes: LongHashSet, nextNodeRecid: Long) { if (left != node.isLeftEdge) throw AssertionError("left does not match $left") //TODO follow link for this assertion // if (right != node.isRightEdge) // throw AssertionError("right does not match $right") //check keys are sorted, no duplicates val keysLen = keySerializer.valueArraySize(node.keys) for (i in 1 until keysLen) { val compare = comparator.compare( keySerializer.valueArrayGet(node.keys, i - 1), keySerializer.valueArrayGet(node.keys, i)) if (compare >= 0) throw AssertionError("Not sorted: " + Arrays.toString(keySerializer.valueArrayToArray(node.keys))) } //iterate over child if (node.isDir) { val child = node.values as LongArray var prevLink = 0L; for (i in child.size - 1 downTo 0) { val recid = child[i] if (knownNodes.contains(recid)) throw AssertionError("recid duplicate: $recid") knownNodes.add(recid) var node = getNode(recid) verifyRecur(node, left = (i == 0) && left, right = (child.size == i + 1) && right, knownNodes = knownNodes, nextNodeRecid = nextNodeRecid) //TODO implement follow link // //follow link until next node is found // while(node.link!=prevLink){ // if(knownNodes.contains(node.link)) // throw AssertionError() // knownNodes.add(node.link) // // node = getNode(node.link) // // verifyRecur(node, left = false, right= node.link==0L, // knownNodes = knownNodes, nextNodeRecid=prevLink) // } prevLink = recid } } } val rootRecid = rootRecid if(leftEdges!=loadLeftEdges()){ throw AssertionError(); } val node = getNode(rootRecid) val knownNodes = LongHashSet.newSetWith(rootRecid) verifyRecur(node, left = true, right = true, knownNodes = knownNodes, nextNodeRecid = 0L) //verify that linked nodes share the same keys on their edges for (leftRecid in leftEdges.toArray()) { if (knownNodes.contains(leftRecid).not()) throw AssertionError() var node = getNode(leftRecid) if (!knownNodes.remove(leftRecid)) throw AssertionError() while (node.isRightEdge.not()) { //TODO enable once links are traced // if(!knownNodes.remove(node.link)) // throw AssertionError() val next = getNode(node.link) if (comparator.compare(node.highKey(keySerializer) as K, keySerializer.valueArrayGet(next.keys, 0)) != 0) throw AssertionError(node.link) node = next } } //TODO enable once links are traced // if(knownNodes.isEmpty.not()) // throw AssertionError(knownNodes) } private fun getNode(nodeRecid: Long) = store.get(nodeRecid, nodeSerializer) ?: throw DBException.DataCorruption("Node not found") private fun nodeToString(nodeRecid:Long?, node:Node):String{ var str = if (node.isDir) "DIR " else "LEAF " if (node.isLeftEdge) str += "L" if (node.isRightEdge) str += "R" if (node.isLastKeyDouble) str += "D" str += " recid=$nodeRecid, link=${node.link}, keys=" + Arrays.toString(keySerializer.valueArrayToArray(node.keys)) + ", " str += if (node.isDir){ "child=" + Arrays.toString(node.children) }else if(valueInline){ "vals=" + Arrays.toString(valueNodeSerializer.valueArrayToArray(node.values)) }else{ val withVals = valueNodeSerializer .valueArrayToArray(node.values) .map{it.toString()+"=>"+valueExpand(it)} .toTypedArray() "extvals=" + Arrays.toString(withVals) } return str } fun printStructure(out: PrintStream) { fun printRecur(nodeRecid: Long, prefix: String) { val node = getNode(nodeRecid); out.println(prefix + nodeToString(nodeRecid, node)) if (node.isDir) { node.children.forEach { printRecur(it, " " + prefix) } } } printRecur(rootRecid, "") } override fun putAll(from: Map) { for (e in from.entries) { put(e.key, e.value) } } override fun putIfAbsentBoolean(key: K?, value: V?): Boolean { if (key == null || value == null) throw NullPointerException() return putIfAbsent(key, value) != null } override fun putIfAbsent(key: K?, value: V?): V? { if (key == null || value == null) throw NullPointerException() return put2(key, value, true) } override fun remove(key: Any?, value: Any?): Boolean { if (key == null || value == null) throw NullPointerException() return removeOrReplace(key as K, value as V, null) != null } override fun replace(key: K?, oldValue: V?, newValue: V?): Boolean { if (key == null || oldValue == null || newValue == null) throw NullPointerException() return removeOrReplace(key, oldValue, newValue) != null } override fun replace(key: K?, value: V?): V? { if (key == null || value == null) throw NullPointerException() return removeOrReplace(key, null, value) } override fun containsKey(key: K): Boolean { return get(key) != null } override fun containsValue(value: V): Boolean { return values.contains(value) } override fun isEmpty(): Boolean { return keys.iterator().hasNext().not() } override val size: Int get() = Math.min(Int.MAX_VALUE.toLong(), sizeLong()).toInt() override fun sizeLong(): Long { if(counterRecid!=0L) return store.get(counterRecid, Serializer.LONG) ?:throw DBException.DataCorruption("Counter not found") var ret = 0L val iter = keys.iterator() while (iter.hasNext()) { iter.next() ret++ } return ret } private fun counterIncrement(i:Int){ if(counterRecid==0L) return do{ val counter = store.get(counterRecid, Serializer.LONG) ?:throw DBException.DataCorruption("Counter not found") }while(store.compareAndSwap(counterRecid, counter, counter+i, Serializer.LONG).not()) } private val descendingMap = DescendingMap(this, null, true, null, false) override fun descendingKeySet(): NavigableSet? { return descendingMap.navigableKeySet() } override fun descendingMap(): ConcurrentNavigableMap? { return descendingMap; } //TODO retailAll etc should use serializers for comparasions, remove AbstractSet and AbstractCollection completely //TODO PERF replace iterator with forEach, much faster indexTree traversal override val entries: MutableSet> = object : AbstractSet>() { override fun add(element: MutableMap.MutableEntry): Boolean { [email protected](element.key, element.value) return true } override fun clear() { [email protected]() } override fun iterator(): MutableIterator> { return [email protected]() } override fun remove(element: MutableMap.MutableEntry?): Boolean { if (element == null || element.key == null || element.value == null) throw NullPointerException() return [email protected](element.key as Any, element.value) } override fun contains(element: MutableMap.MutableEntry): Boolean { val v = [email protected](element.key) ?: return false val value = element.value ?: return false return valueSerializer.equals(value, v) } override fun isEmpty(): Boolean { return [email protected]() } override val size: Int get() = [email protected] } override fun navigableKeySet(): NavigableSet { return keys; } override val keys: NavigableSet = KeySet(this as ConcurrentNavigableMap2, this.hasValues) override val values: MutableCollection = object : AbstractCollection() { override fun clear() { [email protected]() } override fun isEmpty(): Boolean { return [email protected]() } override val size: Int get() = [email protected] override fun iterator(): MutableIterator { return [email protected]() } override fun contains(element: V): Boolean { if (element == null) throw NullPointerException() return super.contains(element) } } abstract class BTreeIterator(val m:BTreeMap){ protected var currentPos = -1 protected var currentLeaf:Node? = null protected var lastReturnedKey: K? = null init{ advanceFrom(m.leftEdges.first!!) } fun hasNext():Boolean = currentLeaf!=null fun remove() { m.remove(lastReturnedKey ?: throw IllegalStateException()) this.lastReturnedKey = null } private fun advanceFrom(recid: Long) { var node: Node? = if(recid==0L) null else m.getNode(recid); // iterate until node is not empty or link is not found while (node != null && m.keySerializer.valueArraySize(node.keys)+node.intLastKeyTwice() == 2 - node.intLeftEdge() - node.intRightEdge()) { node = if (node.isRightEdge) null else m.getNode(node.link) } //set leaf currentLeaf = node currentPos = if (node == null) -1 else 1 - node.intLeftEdge() } protected fun advance(){ val currentLeaf:Node = currentLeaf?:return lastReturnedKey = m.keySerializer.valueArrayGet(currentLeaf.keys, currentPos) as K currentPos++ if(currentPos == m.keySerializer.valueArraySize(currentLeaf.keys)-1+currentLeaf.intRightEdge()+currentLeaf.intLastKeyTwice()){ //reached end of current node, iterate to next advanceFrom(currentLeaf.link) } } } abstract class BTreeBoundIterator( val m: BTreeMap, val lo:K?, val loInclusive:Boolean, val hi:K?, val hiInclusive:Boolean) { protected val hiC = if(hiInclusive) 0 else -1 protected var currentPos = -1 protected var currentLeaf: Node? = null protected var lastReturnedKey: K? = null init { if(lo==null) advanceFrom(m.leftEdges.first!!) else advanceFromLo() } fun hasNext(): Boolean = currentLeaf != null fun remove() { m.remove(lastReturnedKey ?: throw IllegalStateException()) this.lastReturnedKey = null } private fun advanceFrom(recid: Long) { var node: Node? = if (recid == 0L) null else m.getNode(recid); // iterate until node is not empty or link is not found while (node != null && m.keySerializer.valueArraySize(node.keys) + node.intLastKeyTwice() == 2 - node.intLeftEdge() - node.intRightEdge()) { node = if (node.isRightEdge) null else m.getNode(node.link) } //set leaf currentLeaf = node currentPos = if (node == null) -1 else 1 - node.intLeftEdge() checkHiBound() } private fun advanceFromLo() { val key = lo var current = m.rootRecid var A = m.getNode(current) //dive into bottom while (A.isDir) { current = findChild(m.keySerializer, A, m.comparator, key) A = m.getNode(current) } //follow link until necessary while(true){ var pos = m.keySerializer.valueArraySearch(A.keys, key, m.comparator) if(!loInclusive && pos>=1-A.intLeftEdge()) pos++ if(pos<0) pos = -pos-1 if(pos==0 && !A.isLeftEdge) pos++ //check if is last key if(pos< m.keySerializer.valueArraySize(A.keys)-1+A.intLastKeyTwice()+A.intRightEdge()){ currentLeaf = A currentPos = pos; checkHiBound() return } if(A.isRightEdge){ //reached end, cancel iteration currentLeaf = null return } //load next node A = m.getNode(A.link) } } protected fun advance() { val currentLeaf: Node = currentLeaf ?: return lastReturnedKey = m.keySerializer.valueArrayGet(currentLeaf.keys, currentPos) as K currentPos++ if (currentPos == m.keySerializer.valueArraySize(currentLeaf.keys) - 1 + currentLeaf.intRightEdge() + currentLeaf.intLastKeyTwice()) { //reached end of current node, iterate to next advanceFrom(currentLeaf.link) } checkHiBound() } protected fun checkHiBound(){ if(hi==null) return; val leaf = currentLeaf ?:return val currKey = m.keySerializer.valueArrayGet(leaf.keys, currentPos) if(m.comparator.compare(currKey, hi)>hiC){ //reached end, so cancel iteration currentLeaf = null currentPos = -1; } } } fun entryIterator(): MutableIterator> { return object : BTreeIterator(this), MutableIterator> { override fun next(): MutableMap.MutableEntry { val leaf = currentLeaf ?: throw NoSuchElementException() val key = keySerializer.valueArrayGet(leaf.keys, currentPos) val value = valueExpand( valueNodeSerializer.valueArrayGet( leaf.values, currentPos - 1 + leaf.intLeftEdge())) advance() return btreeEntry(key, value) } } } override fun entryIterator(lo:K?,loInclusive:Boolean,hi:K?,hiInclusive:Boolean): MutableIterator> { return object : BTreeBoundIterator(this, lo, loInclusive, hi, hiInclusive), MutableIterator> { override fun next(): MutableMap.MutableEntry { val leaf = currentLeaf ?: throw NoSuchElementException() val key = keySerializer.valueArrayGet(leaf.keys, currentPos) val value = valueExpand( valueNodeSerializer.valueArrayGet( leaf.values, currentPos - 1 + leaf.intLeftEdge())) advance() return btreeEntry(key, value) } } } override fun keyIterator(): MutableIterator { return object : BTreeIterator(this), MutableIterator { override fun next(): K { val leaf = currentLeaf ?: throw NoSuchElementException() val key = keySerializer.valueArrayGet(leaf.keys, currentPos) advance() return key } } } override fun keyIterator(lo:K?,loInclusive:Boolean,hi:K?,hiInclusive:Boolean): MutableIterator { return object : BTreeBoundIterator(this, lo, loInclusive, hi, hiInclusive), MutableIterator { override fun next(): K { val leaf = currentLeaf ?: throw NoSuchElementException() val key = keySerializer.valueArrayGet(leaf.keys, currentPos) advance() return key } } } fun valueIterator(): MutableIterator { return object : BTreeIterator(this), MutableIterator { override fun next(): V? { val leaf = currentLeaf ?: throw NoSuchElementException() val value = valueExpand( valueNodeSerializer.valueArrayGet( leaf.values, currentPos - 1 + leaf.intLeftEdge())) advance() return value } } } override fun valueIterator(lo:K?,loInclusive:Boolean,hi:K?,hiInclusive:Boolean): MutableIterator { return object : BTreeBoundIterator(this, lo, loInclusive, hi, hiInclusive), MutableIterator { override fun next(): V? { val leaf = currentLeaf ?: throw NoSuchElementException() val value = valueExpand( valueNodeSerializer.valueArrayGet( leaf.values, currentPos - 1 + leaf.intLeftEdge())) advance() return value } } } fun descendingLeafIterator(hi: K?):Iterator{ class INode( var linked:Deque = LinkedList(), var node:Node, var nodePos:Int, var linkLimit:Long ){} return object : Iterator{ var nextNode:Node? = null; val stack:Deque = LinkedList() val leafLinkedStack:Deque = LinkedList() var linkRecidLimit = 0L init{ if(hi!=null){ init(hi) }else init() } fun init(){ var node = getNode(rootRecid) while(node.isDir){ val linkedStack = LinkedList() while(node.isRightEdge.not()){ linkedStack.add(node) node = getNode(node.link) } val inode = INode( linked=linkedStack, node=node, nodePos = node.children.size-2, linkLimit = linkRecidLimit) stack.add(inode) linkRecidLimit = node.children[node.children.size-1] node = getNode(linkRecidLimit) } //fill leafLinkedStack while(node.isRightEdge.not()){ leafLinkedStack.add(node) node = getNode(node.link) } nextNode = node; } fun init(hi:K){ var node = getNode(rootRecid) while(node.isDir){ var pos = keySerializer.valueArraySearch(node.keys, hi, comparator) if(pos<0) pos=-pos-1 pos += -1 + node.intLeftEdge() val linkedStack = LinkedList() //follow link until needed while(pos>=keySerializer.valueArraySize(node.keys) && node.link!=0L){ linkedStack.add(node) node = getNode(node.link) pos = keySerializer.valueArraySearch(node.keys, hi, comparator) if(pos<0) pos=-pos-1 pos += -1 + node.intLeftEdge() } val inode = INode( linked=linkedStack, node=node, nodePos = pos-1, linkLimit = linkRecidLimit) stack.add(inode) linkRecidLimit = node.children[Math.min(pos, node.children.size-1)] node = getNode(linkRecidLimit) } var pos = keySerializer.valueArraySearch(node.keys, hi, comparator) if(pos<0) pos=-pos-1 pos += -1 + node.intLeftEdge() //fill leafLinkedStack while(pos>=keySerializer.valueArraySize(node.keys) && node.link!=0L){ leafLinkedStack.add(node) node = getNode(node.link) pos = keySerializer.valueArraySearch(node.keys, hi, comparator) if(pos<0) pos=-pos-1 pos += -1 + node.intLeftEdge() } nextNode = node; } fun advance(){ //try to get previous value from linked leaf nextNode = leafLinkedStack.pollFirst(); if(nextNode!=null) return if(CC.ASSERT && leafLinkedStack.isEmpty().not()) throw AssertionError() fun stackMove(){ if(stack.isEmpty() || stack.last.nodePos>-1) { return } //try to move on linked val linked = stack.last.linked.pollLast() if(linked!=null){ stack.last.node = linked stack.last.nodePos = linked.children.size-1 return } val limit = stack.last().linkLimit stack.pollLast() //try upper levels stackMove() if(stack.isEmpty()){ return } val linkedStack = LinkedList() val nodeRecid = stack.last.node.children[stack.last.nodePos--] var node = getNode(nodeRecid) while(node.link != limit){ if(CC.ASSERT && hi!=null && comparator.compare(hi,keySerializer.valueArrayGet(node.keys, 0))<0){ throw AssertionError() } linkedStack.add(node) node = getNode(node.link) } val inode = INode( linked = linkedStack, node=node, nodePos = node.children.size-1, linkLimit=nodeRecid ) stack.add(inode) } stackMove() if(stack.isEmpty()){ //terminate iteration nextNode = null return; } //no more leaf records, ascend one level and find previous leaf val inode = stack.last val childRecid = inode.node.children[inode.nodePos--] var node = getNode(childRecid) //follow link at leaf level, until linkRecidLimit while(node.link!=linkRecidLimit){ leafLinkedStack.add(node) node = getNode(node.link) } nextNode = node; //start of this linked sequence becomes new limit linkRecidLimit = childRecid } override fun hasNext(): Boolean { return nextNode != null } override fun next(): Node { val ret = nextNode ?: throw NoSuchElementException() advance() if(CC.ASSERT && nextNode!=null){ val currKey = keySerializer.valueArrayGet(ret.keys, 0) val nextKey = nextNode!!.highKey(keySerializer) if(comparator.compare(nextKey, currKey)>0){ throw AssertionError("wrong reverse iteration") } } return ret; } } } abstract class DescendingIterator(val m:BTreeMap){ protected val descLeafIter = m.descendingLeafIterator(null) protected var currentPos = -1 protected var currentLeaf:Node? = null protected var lastReturnedKey: K? = null init{ advanceNode(); } fun hasNext():Boolean = currentLeaf!=null fun remove() { m.remove(lastReturnedKey ?: throw IllegalStateException()) this.lastReturnedKey = null } protected fun advanceNode(){ if(descLeafIter.hasNext().not()) { currentLeaf = null currentPos = -1 return } var node:Node do{ node = descLeafIter.next() }while(node.isEmpty(m.keySerializer) && descLeafIter.hasNext()) if(node.isEmpty(m.keySerializer)){ //reached end currentPos = -1 currentLeaf = null }else{ currentLeaf = node currentPos = m.keySerializer.valueArraySize(node.keys)-2+node.intLastKeyTwice()+node.intRightEdge() } } protected fun advance(){ val currentLeaf:Node = currentLeaf?:return lastReturnedKey = m.keySerializer.valueArrayGet(currentLeaf.keys, currentPos) as K currentPos-- if(currentPos< 1-currentLeaf.intLeftEdge()){ advanceNode() } } } abstract class DescendingBoundIterator( val m:BTreeMap, val lo:K?, val loInclusive:Boolean, val hi:K?, val hiInclusive: Boolean ){ protected val descLeafIter = m.descendingLeafIterator(hi) protected var currentPos = -1 protected var currentLeaf:Node? = null protected var lastReturnedKey: K? = null protected val loC = if(loInclusive) 0 else -1 init{ advanceNode(); } fun hasNext():Boolean = currentLeaf!=null fun remove() { m.remove(lastReturnedKey ?: throw IllegalStateException()) this.lastReturnedKey = null } protected fun advanceNode(){ val iter = descLeafIter val key = hi val inclusive = hiInclusive while(iter.hasNext()){ val node = iter.next() if(node.isEmpty(m.keySerializer)) continue var pos=-1; val maxPos = m.keySerializer.valueArraySize(node.keys) - 2 + node.intLastKeyTwice() + node.intRightEdge() if(key==null) { pos = maxPos }else{ pos = m.keySerializer.valueArraySearch(node.keys, key, m.comparator) if(pos<0) pos=-pos-2 else if(!inclusive) pos-- if(pos<1-node.intLeftEdge()) continue pos = Math.min(pos, maxPos) } currentLeaf = node currentPos = pos checkLoBound() return } currentLeaf = null } protected fun advance(){ val currentLeaf:Node = currentLeaf?:return lastReturnedKey = m.keySerializer.valueArrayGet(currentLeaf.keys, currentPos) as K currentPos-- if(currentPos< 1-currentLeaf.intLeftEdge()){ advanceNode() } checkLoBound() } protected fun checkLoBound(){ if(lo==null) return; val leaf = currentLeaf ?:return val currKey = m.keySerializer.valueArrayGet(leaf.keys, currentPos) if (m.comparator.compare(lo, currKey) > loC) { //reached end, so cancel iteration currentLeaf = null currentPos = -1; } } } override fun descendingEntryIterator(): MutableIterator> { return object : DescendingIterator(this), MutableIterator> { override fun next(): MutableMap.MutableEntry { val leaf = currentLeaf ?: throw NoSuchElementException() val key = keySerializer.valueArrayGet(leaf.keys, currentPos) val value = valueExpand( valueNodeSerializer.valueArrayGet( leaf.values, currentPos - 1 + leaf.intLeftEdge())) advance() return btreeEntry(key, value) } } } override fun descendingEntryIterator(lo:K?,loInclusive:Boolean,hi:K?,hiInclusive:Boolean): MutableIterator> { return object : DescendingBoundIterator(this, lo, loInclusive, hi, hiInclusive), MutableIterator> { override fun next(): MutableMap.MutableEntry { val leaf = currentLeaf ?: throw NoSuchElementException() val key = keySerializer.valueArrayGet(leaf.keys, currentPos) val value = valueExpand( valueNodeSerializer.valueArrayGet( leaf.values, currentPos - 1 + leaf.intLeftEdge())) advance() return btreeEntry(key, value) } } } override fun descendingKeyIterator(): MutableIterator { return object : DescendingIterator(this), MutableIterator { override fun next(): K { val leaf = currentLeaf ?: throw NoSuchElementException() val key = keySerializer.valueArrayGet(leaf.keys, currentPos) advance() return key } } } override fun descendingKeyIterator(lo:K?,loInclusive:Boolean,hi:K?,hiInclusive:Boolean): MutableIterator { return object : DescendingBoundIterator(this, lo, loInclusive, hi, hiInclusive), MutableIterator { override fun next(): K { val leaf = currentLeaf ?: throw NoSuchElementException() val key = keySerializer.valueArrayGet(leaf.keys, currentPos) advance() return key } } } override fun descendingValueIterator(): MutableIterator { return object : DescendingIterator(this), MutableIterator { override fun next(): V? { val leaf = currentLeaf ?: throw NoSuchElementException() val value = valueExpand( valueNodeSerializer.valueArrayGet( leaf.values, currentPos - 1 + leaf.intLeftEdge())) advance() return value } } } override fun descendingValueIterator(lo:K?,loInclusive:Boolean,hi:K?,hiInclusive:Boolean): MutableIterator { return object : DescendingBoundIterator(this, lo, loInclusive, hi, hiInclusive), MutableIterator { override fun next(): V? { val leaf = currentLeaf ?: throw NoSuchElementException() val value = valueExpand( valueSerializer.valueArrayGet( leaf.values, currentPos - 1 + leaf.intLeftEdge())) advance() return value } } } protected fun btreeEntry(key: K, valueOrig: V?): MutableMap.MutableEntry { return object : MutableMap.MutableEntry { override val key: K get() = key override val value: V? get() = valueCached ?: this@BTreeMap[key] /** cached value, if null get value from map */ private var valueCached: V? = valueOrig; override fun hashCode(): Int { return keySerializer.hashCode(this.key!!, 0) xor valueSerializer.hashCode(this.value!!, 0) } override fun setValue(newValue: V?): V? { valueCached = null; return put(key, newValue) } override fun equals(other: Any?): Boolean { if (other !is Map.Entry<*, *>) return false val okey = other.key ?: return false val ovalue = other.value ?: return false try { return comparator.compare(key, okey as K)==0 && valueSerializer.equals(this.value!!, ovalue as V) } catch(e: ClassCastException) { return false } } override fun toString(): String { return "MapEntry[${key}=${value}]" } } } override fun hashCode(): Int { var h = 0 val i = entries.iterator() while (i.hasNext()) h += i.next().hashCode() return h } override fun equals(other: Any?): Boolean { if (other === this) return true if (other !is java.util.Map<*, *>) return false if (other.size() != size) return false try { val i = entries.iterator() while (i.hasNext()) { val e = i.next() val key = e.key val value = e.value if (value == null) { if (!(other.get(key) == null && other.containsKey(key))) return false } else { if (value != other.get(key)) return false } } } catch (unused: ClassCastException) { return false } catch (unused: NullPointerException) { return false } return true } override fun isClosed(): Boolean { return store.isClosed } override fun forEach(action: BiConsumer?) { if (action == null) throw NullPointerException() var node = getNode(leftEdges.first) while (true) { val limit = keySerializer.valueArraySize(node.keys) - 1 + node.intRightEdge() + node.intLastKeyTwice() for (i in 1 - node.intLeftEdge() until limit) { val key = keySerializer.valueArrayGet(node.keys, i) val value = valueExpand(valueNodeSerializer.valueArrayGet(node.values, i - 1 + node.intLeftEdge())) if(value!=null) action.accept(key, value) } if (node.isRightEdge) return node = getNode(node.link) } } override fun forEachKey(procedure: (K) -> Unit) { if (procedure == null) throw NullPointerException() var node = getNode(leftEdges.first) while (true) { val limit = keySerializer.valueArraySize(node.keys) - 1 + node.intRightEdge() + node.intLastKeyTwice() for (i in 1 - node.intLeftEdge() until limit) { val key = keySerializer.valueArrayGet(node.keys, i) procedure(key) } if (node.isRightEdge) return node = getNode(node.link) } } override fun forEachValue(procedure: (V) -> Unit) { if (procedure == null) throw NullPointerException() var node = getNode(leftEdges.first) while (true) { val limit = keySerializer.valueArraySize(node.keys) - 1 + node.intRightEdge() + node.intLastKeyTwice() for (i in 1 - node.intLeftEdge() until limit) { val value = valueExpand(valueNodeSerializer.valueArrayGet(node.values, i - 1 + node.intLeftEdge())) if(value!=null) procedure(value) } if (node.isRightEdge) return node = getNode(node.link) } } @Throws(ObjectStreamException::class) private fun writeReplace(): Any { val ret = ConcurrentSkipListMap() forEach { k, v -> ret.put(k, v) } return ret } fun prefixSubMap(prefix:K): ConcurrentNavigableMap { return prefixSubMap(prefix, true) } fun prefixSubMap(prefix:K, inclusive:Boolean): ConcurrentNavigableMap{ if(prefix==null) throw NullPointerException() if(comparator!=keySerializer) throw UnsupportedOperationException("prefixSubMap is not supported with custom comparators") val hiKey = keySerializer.nextValue(prefix) return SubMap(this, prefix, inclusive, hiKey, false) } override fun subMap(fromKey: K?, fromInclusive: Boolean, toKey: K?, toInclusive: Boolean): ConcurrentNavigableMap { if (fromKey == null || toKey == null) throw NullPointerException() return SubMap(this, fromKey, fromInclusive, toKey, toInclusive) } override fun headMap(toKey: K?, inclusive: Boolean): ConcurrentNavigableMap { if (toKey == null) throw NullPointerException() return SubMap(this, null, false, toKey, inclusive) } override fun tailMap(fromKey: K?, inclusive: Boolean): ConcurrentNavigableMap { if (fromKey == null) throw NullPointerException() return SubMap(this, fromKey, inclusive, null, false) } override fun subMap(fromKey: K, toKey: K): ConcurrentNavigableMap { return subMap(fromKey, true, toKey, false) } override fun headMap(toKey: K): ConcurrentNavigableMap { return headMap(toKey, false) } override fun tailMap(fromKey: K): ConcurrentNavigableMap { return tailMap(fromKey, true) } override fun comparator(): Comparator? { return comparator } override fun firstEntry(): MutableMap.MutableEntry? { //get first node var node = getNode(leftEdges.first) //until empty, follow link while (node.isEmpty(keySerializer)) { if (node.isRightEdge) return null; node = getNode(node.link) } val key = keySerializer.valueArrayGet(node.keys, 1 - node.intLeftEdge()) val value = valueExpand(valueNodeSerializer.valueArrayGet(node.values, 0)) //TODO SimpleImmutableEntry etc does not use key/valueSerializer hash code, this is at multiple places return AbstractMap.SimpleImmutableEntry(key as K, value as V) } override fun lastEntry(): MutableMap.MutableEntry? { val iter = descendingLeafIterator(null) while(iter.hasNext()){ val node = iter.next() if(node.isEmpty(keySerializer)) { continue } val key = keySerializer.valueArrayGet( node.keys, keySerializer.valueArraySize(node.keys) - 2 + node.intLastKeyTwice() + node.intRightEdge() ) val value = valueExpand( valueNodeSerializer.valueArrayGet( node.values, valueNodeSerializer.valueArraySize(node.values) - 1) ) return AbstractMap.SimpleImmutableEntry(key, value) } return null } override fun firstKey2(): K? { //get first node var node = getNode(leftEdges.first) //until empty, follow link while (node.isEmpty(keySerializer)) { if (node.isRightEdge) return null; node = getNode(node.link) } return keySerializer.valueArrayGet(node.keys, 1 - node.intLeftEdge()) } override fun lastKey2(): K? { val iter = descendingLeafIterator(null) while(iter.hasNext()){ val node = iter.next() if(node.isEmpty(keySerializer)) { continue } return keySerializer.valueArrayGet( node.keys, keySerializer.valueArraySize(node.keys) - 2 + node.intLastKeyTwice() + node.intRightEdge() ) } return null } override fun firstKey(): K { return firstKey2()?: throw NoSuchElementException() } override fun lastKey(): K { return lastKey2()?: throw NoSuchElementException() } override fun pollFirstEntry(): MutableMap.MutableEntry? { while (true) { val e = firstEntry() ?: return null if(remove(e.key, e.value)) return AbstractMap.SimpleImmutableEntry(e.key, e.value); } } override fun pollLastEntry(): MutableMap.MutableEntry? { while (true) { val e = lastEntry() ?: return null if(remove(e.key, e.value)) return AbstractMap.SimpleImmutableEntry(e.key, e.value); } } override fun findHigher(key: K?, inclusive: Boolean): MutableMap.MutableEntry? { var current = rootRecid var A = getNode(current) //dive into bottom while (A.isDir) { current = findChild(keySerializer, A, comparator, key) A = getNode(current) } //follow link until necessary while(true){ var pos = keySerializer.valueArraySearch(A.keys, key, comparator) if(!inclusive && pos>=1-A.intLeftEdge()) pos++ if(pos<0) pos = -pos-1 if(pos==0 && !A.isLeftEdge) pos++ //check if is last key if(pos< keySerializer.valueArraySize(A.keys)-1+A.intLastKeyTwice()+A.intRightEdge()){ val key = keySerializer.valueArrayGet(A.keys, pos) val value = valueExpand(leafGet(A, pos, keySerializer, valueNodeSerializer)) return AbstractMap.SimpleImmutableEntry(key, value as V) } if(A.isRightEdge){ //reached end, cancel iteration return null } //load next node A = getNode(A.link) } } override fun findLower(key: K?, inclusive: Boolean): MutableMap.MutableEntry? { val iter = descendingLeafIterator(key) while(iter.hasNext()){ val node = iter.next() if(node.isEmpty(keySerializer)) continue var pos = keySerializer.valueArraySearch(node.keys, key, comparator) if(pos==-1) continue if(pos==0 && !inclusive) continue if(pos>=1-node.intLeftEdge() && !inclusive) pos-- if(pos>=keySerializer.valueArraySize(node.keys)-1+node.intRightEdge()+node.intLastKeyTwice()) pos-- if(pos>=1-node.intLeftEdge()){ //node was found val key = keySerializer.valueArrayGet(node.keys, pos) val value = valueExpand(valueNodeSerializer.valueArrayGet(node.values, pos - 1 + node.intLeftEdge())) return AbstractMap.SimpleImmutableEntry(key, value) } if(inclusive && pos == 1-node.intLeftEdge()){ pos = 1-node.intLeftEdge() val key = keySerializer.valueArrayGet(node.keys, pos) val value = valueExpand(valueNodeSerializer.valueArrayGet(node.values, pos-1+node.intLeftEdge())) return AbstractMap.SimpleImmutableEntry(key, value) } if(pos<0){ pos = - pos - 2 if(pos>=keySerializer.valueArraySize(node.keys)-1+node.intRightEdge()+node.intLastKeyTwice()) pos-- if(pos<1-node.intLeftEdge()) continue val key = keySerializer.valueArrayGet(node.keys, pos) val value = valueExpand(valueNodeSerializer.valueArrayGet(node.values, pos - 1 + node.intLeftEdge())) return AbstractMap.SimpleImmutableEntry(key, value) } } return null } override fun findHigherKey(key: K?, inclusive: Boolean): K? { var current = rootRecid var A = getNode(current) //dive into bottom while (A.isDir) { current = findChild(keySerializer, A, comparator, key) A = getNode(current) } //follow link until necessary while(true){ var pos = keySerializer.valueArraySearch(A.keys, key, comparator) if(!inclusive && pos>=1-A.intLeftEdge()) pos++ if(pos<0) pos = -pos-1 if(pos==0 && !A.isLeftEdge) pos++ //check if is last key if(pos< keySerializer.valueArraySize(A.keys)-1+A.intLastKeyTwice()+A.intRightEdge()){ return keySerializer.valueArrayGet(A.keys, pos) } if(A.isRightEdge){ //reached end, cancel iteration return null } //load next node A = getNode(A.link) } } override fun findLowerKey(key: K?, inclusive: Boolean): K? { val iter = descendingLeafIterator(key) while(iter.hasNext()){ val node = iter.next() if(node.isEmpty(keySerializer)) continue var pos = keySerializer.valueArraySearch(node.keys, key, comparator) if(pos==-1) continue if(pos==0 && !inclusive) continue if(pos>=1-node.intLeftEdge() && !inclusive) pos-- if(pos>=keySerializer.valueArraySize(node.keys)-1+node.intRightEdge()+node.intLastKeyTwice()) pos-- if(pos>=1-node.intLeftEdge()){ //node was found return keySerializer.valueArrayGet(node.keys, pos) } if(inclusive && pos == 1-node.intLeftEdge()){ pos = 1-node.intLeftEdge() return keySerializer.valueArrayGet(node.keys, pos) } if(pos<0){ pos = - pos - 2 if(pos>=keySerializer.valueArraySize(node.keys)-1+node.intRightEdge()+node.intLastKeyTwice()) pos-- if(pos<1-node.intLeftEdge()) continue return keySerializer.valueArrayGet(node.keys, pos) } } return null } override fun lowerEntry(key: K?): MutableMap.MutableEntry? { if (key == null) throw NullPointerException() return findLower(key, false) } override fun lowerKey(key: K): K? { return findLowerKey(key, false) } override fun floorEntry(key: K?): MutableMap.MutableEntry? { if (key == null) throw NullPointerException() return findLower(key, true) } override fun floorKey(key: K): K? { return findLowerKey(key, true) } override fun ceilingEntry(key: K?): MutableMap.MutableEntry? { if (key == null) throw NullPointerException() return findHigher(key, true) } override fun ceilingKey(key: K?): K? { if (key == null) throw NullPointerException() return findHigherKey(key, true) } override fun higherEntry(key: K?): MutableMap.MutableEntry? { if (key == null) throw NullPointerException() return findHigher(key, false) } override fun higherKey(key: K?): K? { if (key == null) throw NullPointerException() return findHigherKey(key, false) } override fun clear() { val iter = keys.iterator(); while (iter.hasNext()) { iter.next() iter.remove() } } override fun checkThreadSafe(){ if(isThreadSafe.not()) throw AssertionError(); store.checkThreadSafe() } //TODO PERF optimize clear, traverse nodes and clear each node in one step // override fun clear() { // val hasListeners = modListeners.size > 0 // var current = engine.get(rootRecidRef, Serializer.RECID) // // var A = engine.get(current, nodeSerializer) // //$DELAY$ // while (!A.isLeaf()) { // current = A.child(0) // //$DELAY$ // A = engine.get(current, nodeSerializer) // } // // var old: Long = 0 // try { // while (true) { // //$DELAY$ // //lock nodes // lock(nodeLocks, current) // if (old != 0) { // //$DELAY$ // unlock(nodeLocks, old) // } // //$DELAY$ // //notify about deletion // val size = A.keysLen(keySerializer) - 1 // if (hasListeners) { // //$DELAY$ // for (i in 1..size - 1) { // var `val` = A.`val`(i - 1, valueNodeSerializer) // `val` = valExpand(`val`) // //$DELAY$ // notify(A.key(keySerializer, i) as K?, `val` as V, null) // } // } // // //remove all node content // A = (A as LeafNode).copyClear(keySerializer, valueNodeSerializer) // //$DELAY$ // engine.update(current, A, nodeSerializer) // // //move to next link // old = current // //$DELAY$ // current = A.next() // if (current == 0) { // //end reached // //$DELAY$ // unlock(nodeLocks, old) // //$DELAY$ // return // } // //$DELAY$ // A = engine.get(current, nodeSerializer) // } // } catch (e: RuntimeException) { // unlockAll(nodeLocks) // throw e // } catch (e: Exception) { // unlockAll(nodeLocks) // throw RuntimeException(e) // } // // } // }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy