![JAR search and dependency download from the Maven repository](/logo.png)
swaydb.core.segment.KeyMatcher.scala Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2020 Simer JS Plaha ([email protected] - @simerplaha)
*
* This file is a part of SwayDB.
*
* SwayDB 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.
*
* SwayDB 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 SwayDB. If not, see .
*
* Additional permission under the GNU Affero GPL version 3 section 7:
* If you modify this Program or any covered work, only by linking or combining
* it with separate works, the licensors of this Program grant you additional
* permission to convey the resulting work.
*/
package swaydb.core.segment
import swaydb.core.data.Persistent
import swaydb.core.segment.KeyMatcher.Result.{AheadOrNoneOrEnd, BehindFetchNext, BehindStopped, Matched}
import swaydb.data.order.KeyOrder
import swaydb.data.slice.Slice
private[core] sealed trait KeyMatcher {
def key: Slice[Byte]
def isHigher: Boolean
def apply(previous: Persistent.Partial,
next: Persistent.PartialOption,
hasMore: Boolean): KeyMatcher.Result
def keyOrder: KeyOrder[Slice[Byte]]
def matchOnly: Boolean
}
private[core] object KeyMatcher {
sealed trait Result
object Result {
sealed trait Complete extends Result
sealed trait InComplete extends Result
class Matched(val result: Persistent.Partial) extends Complete
sealed trait Behind
final object BehindFetchNext extends InComplete with Behind
/**
* Used as outcome for matchOnly searches like *seekOne functions.
* This result indicates that seek is behind and could continue but was stopped early.
*/
final object BehindStopped extends Complete with Behind
final object AheadOrNoneOrEnd extends Complete
}
sealed trait Bounded extends KeyMatcher
sealed trait Get extends KeyMatcher {
def matchOrStop: Get.MatchOnly =
new Getter(
key = key,
matchOnly = true
)(keyOrder)
}
object Get {
def apply(key: Slice[Byte])(implicit keyOrder: KeyOrder[Slice[Byte]]): Get =
new Getter(
key = key,
matchOnly = false
)
sealed trait Bounded extends KeyMatcher.Bounded
object MatchOnly {
def apply(key: Slice[Byte])(implicit keyOrder: KeyOrder[Slice[Byte]]): Get.MatchOnly =
new Getter(
key = key,
matchOnly = true
)(keyOrder)
}
sealed trait MatchOnly extends Bounded {
def matchOnly: Boolean
}
def matchMutateForBinarySearch(key: Slice[Byte],
partialKeyValue: Persistent.Partial.Fixed)(implicit keyOrder: KeyOrder[Slice[Byte]]): Unit = {
val matchResult = keyOrder.compare(key, partialKeyValue.key)
if (matchResult == 0)
partialKeyValue.isBinarySearchMatched = true
else if (matchResult > 0)
partialKeyValue.isBinarySearchBehind = true
else
partialKeyValue.isBinarySearchAhead = true
}
def matchMutateForBinarySearch(key: Slice[Byte],
range: Persistent.Partial.Range)(implicit keyOrder: KeyOrder[Slice[Byte]]): Unit = {
val fromKeyMatch = keyOrder.compare(key, range.fromKey)
var compared: Boolean = false
var toKeyCompare: Int = 0
def toKeyMatch: Int =
if (compared) {
toKeyCompare
} else {
toKeyCompare = keyOrder.compare(key, range.toKey)
compared = true
toKeyCompare
}
if (fromKeyMatch >= 0 && toKeyMatch < 0) //is within the range
range.isBinarySearchMatched = true
else if (toKeyMatch >= 0)
range.isBinarySearchBehind = true
else
range.isBinarySearchAhead = true
}
def matchForHashIndex(key: Slice[Byte],
partialKeyValue: Persistent.Partial.Fixed)(implicit keyOrder: KeyOrder[Slice[Byte]]): Boolean =
keyOrder.equiv(key, partialKeyValue.key)
def matchForHashIndex(key: Slice[Byte],
range: Persistent.Partial.Range)(implicit keyOrder: KeyOrder[Slice[Byte]]): Boolean = {
val fromKeyMatch = keyOrder.compare(key, range.fromKey)
fromKeyMatch == 0 || (fromKeyMatch > 0 && keyOrder.lt(key, range.toKey))
}
}
//private to disallow creating hashIndex Get from here.
private class Getter(val key: Slice[Byte],
val matchOnly: Boolean)(implicit val keyOrder: KeyOrder[Slice[Byte]]) extends Get with Get.MatchOnly {
override def isHigher: Boolean =
false
override def apply(previous: Persistent.Partial,
next: Persistent.PartialOption,
hasMore: Boolean): KeyMatcher.Result =
next.getOrElseC(previous) match {
case fixed: Persistent.Partial.Fixed =>
val matchResult = keyOrder.compare(key, fixed.key)
if (matchResult == 0)
new Matched(fixed)
else if (matchResult > 0 && hasMore)
if (matchOnly)
BehindStopped
else
BehindFetchNext
else
AheadOrNoneOrEnd
case range: Persistent.Partial.Range =>
val fromKeyMatch = keyOrder.compare(key, range.fromKey)
val toKeyMatch = keyOrder.compare(key, range.toKey)
if (fromKeyMatch >= 0 && toKeyMatch < 0) //is within the range
new Matched(range)
else if (toKeyMatch >= 0 && hasMore)
if (matchOnly)
BehindStopped
else
BehindFetchNext
else
AheadOrNoneOrEnd
}
}
sealed trait Lower extends KeyMatcher {
def matchOrStop: Lower.MatchOnly =
new LowerMatcher(
key = key,
matchOnly = true
)(keyOrder)
}
object Lower {
def apply(key: Slice[Byte])(implicit keyOrder: KeyOrder[Slice[Byte]]): Lower =
new LowerMatcher(
key = key,
matchOnly = false
)
sealed trait Bounded extends KeyMatcher.Bounded
object MatchOnly {
def apply(key: Slice[Byte])(implicit keyOrder: KeyOrder[Slice[Byte]]): Lower.MatchOnly =
new LowerMatcher(
key = key,
matchOnly = true
)(keyOrder)
}
sealed trait MatchOnly extends Bounded {
def matchOnly: Boolean
}
}
private class LowerMatcher(val key: Slice[Byte],
val matchOnly: Boolean)(implicit val keyOrder: KeyOrder[Slice[Byte]]) extends Lower with Lower.MatchOnly {
override def isHigher: Boolean =
false
override def apply(previous: Persistent.Partial,
next: Persistent.PartialOption,
hasMore: Boolean): KeyMatcher.Result =
next match {
case next: Persistent.Partial =>
val nextCompare = keyOrder.compare(next.key, key)
if (nextCompare >= 0)
if (keyOrder.compare(previous.key, key) < 0)
new Matched(previous)
else
AheadOrNoneOrEnd
else if (nextCompare < 0)
if (hasMore)
next match {
case range: Persistent.Partial.Range if keyOrder.compare(key, range.toKey) <= 0 =>
new Matched(next)
case _ =>
if (matchOnly)
BehindStopped
else
BehindFetchNext
}
else
new Matched(next)
else
AheadOrNoneOrEnd
case Persistent.Partial.Null =>
val previousCompare = keyOrder.compare(previous.key, key)
if (previousCompare == 0)
AheadOrNoneOrEnd
else if (previousCompare < 0)
if (hasMore)
previous match {
case range: Persistent.Partial.Range if keyOrder.compare(key, range.toKey) <= 0 =>
new Matched(previous)
case _ =>
BehindFetchNext
}
else
new Matched(previous)
else
AheadOrNoneOrEnd
}
}
sealed trait Higher extends KeyMatcher {
def matchOrStop: Higher.MatchOnly =
new HigherMatcher(
key = key,
matchOnly = true
)(keyOrder)
}
object Higher {
def apply(key: Slice[Byte])(implicit keyOrder: KeyOrder[Slice[Byte]]): Higher =
new HigherMatcher(
key = key,
matchOnly = false
)
sealed trait Bounded extends KeyMatcher.Bounded
object MatchOnly {
def apply(key: Slice[Byte])(implicit keyOrder: KeyOrder[Slice[Byte]]): Higher.MatchOnly =
new HigherMatcher(
key = key,
matchOnly = true
)(keyOrder)
}
sealed trait MatchOnly extends Bounded {
def matchOnly: Boolean
}
}
private class HigherMatcher(val key: Slice[Byte],
val matchOnly: Boolean)(implicit val keyOrder: KeyOrder[Slice[Byte]]) extends Higher with Higher.MatchOnly {
override def isHigher: Boolean =
true
override def apply(previous: Persistent.Partial,
next: Persistent.PartialOption,
hasMore: Boolean): KeyMatcher.Result = {
val keyValue = next getOrElseC previous
val nextCompare = keyOrder.compare(keyValue.key, key)
if (nextCompare > 0)
new Matched(keyValue)
else if (nextCompare <= 0)
keyValue match {
case range: Persistent.Partial.Range if keyOrder.compare(key, range.toKey) < 0 =>
new Matched(keyValue)
case _ =>
if (hasMore)
if (matchOnly)
BehindStopped
else
BehindFetchNext
else
AheadOrNoneOrEnd
}
else
AheadOrNoneOrEnd
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy