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

dev.tauri.choam.internal.mcas.MutDescriptor.scala Maven / Gradle / Ivy

/*
 * SPDX-License-Identifier: Apache-2.0
 * Copyright 2016-2024 Daniel Urban and contributors listed in NOTICE.txt
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package dev.tauri.choam
package internal
package mcas

import scala.util.hashing.MurmurHash3

import emcas.EmcasDescriptor

final class MutDescriptor private (
  private[this] val map: LogMapMut[Any],
  private[this] var _validTs: Long,
  private[this] var _versionIncr: Long,
) extends AbstractDescriptor {

  final override type D = MutDescriptor

  final override def readOnly: Boolean =
    this.map.definitelyReadOnly

  final override def validTs: Long =
    this._validTs

  final override def versionIncr: Long =
    this._versionIncr

  final override def toImmutable: Descriptor = {
    Descriptor.fromLogMapAndVer(
      map = this.map.copyToImmutable(),
      validTs = this.validTs,
      versionIncr = this.versionIncr,
    )
  }

  protected final override def hamt: AbstractHamt[_, _, _, _, _, _] =
    this.map

  private[mcas] final override def hasVersionCas: Boolean =
    false

  private[mcas] final override def addVersionCas(commitTsRef: MemoryLocation[Long]): AbstractDescriptor.Aux[MutDescriptor] = {
    impossible("MutDescriptor#addVersionCas")
  }

  private[choam] final override def getOrElseNull[A](ref: MemoryLocation[A]): LogEntry[A] = {
    this.map.asInstanceOf[LogMapMut[A]].getOrElseNull(ref.id)
  }

  private[choam] final override def add[A](desc: LogEntry[A]): AbstractDescriptor.Aux[MutDescriptor] = {
    // Note, that it is important, that we don't allow
    // adding an already included ref; the Exchanger
    // depends on this behavior:
    this.map.insert(desc.cast[Any])
    this
  }

  private[choam] final override def overwrite[A](desc: LogEntry[A]): AbstractDescriptor.Aux[MutDescriptor] = {
    require(desc.version <= this.validTs)
    this.map.update(desc.cast[Any])
    this
  }

  private[choam] final override def addOrOverwrite[A](desc: LogEntry[A]): AbstractDescriptor.Aux[MutDescriptor] = {
    require(desc.version <= this.validTs)
    this.map.upsert(desc.cast[Any])
    this
  }

  private[choam] final override def computeIfAbsent[A, T](
    ref: MemoryLocation[A],
    tok: T,
    visitor: Hamt.EntryVisitor[MemoryLocation[A], LogEntry[A], T],
  ): MutDescriptor = {
    this.map.computeIfAbsent(ref.cast[Any], tok, visitor.asInstanceOf[Hamt.EntryVisitor[MemoryLocation[Any], LogEntry[Any], T]])
    this
  }

  private[choam] final override def computeOrModify[A, T](
    ref: MemoryLocation[A],
    tok: T,
    visitor: Hamt.EntryVisitor[MemoryLocation[A],LogEntry[A],T],
  ): MutDescriptor = {
    this.map.computeOrModify(ref.cast[Any], tok, visitor.asInstanceOf[Hamt.EntryVisitor[MemoryLocation[Any], LogEntry[Any], T]])
    this
  }

  /**
   * Tries to revalidate `this` based on the current
   * versions of the refs it contains.
   *
   * @return true, iff `this` is still valid.
   */
  private[mcas] final override def revalidate(ctx: Mcas.ThreadContext): Boolean = {
    this.map.revalidate(ctx)
  }

  private[mcas] final override def validateAndTryExtend(
    commitTsRef: MemoryLocation[Long],
    ctx: Mcas.ThreadContext,
    additionalHwd: LogEntry[_],
  ): AbstractDescriptor.Aux[MutDescriptor] = {
    impossible("MutDescriptor#validateAndTryExtend")
  }

  private[mcas] final override def validateAndTryExtendVer(
    currentTs: Long,
    ctx: Mcas.ThreadContext,
    additionalHwd: LogEntry[_]
  ): AbstractDescriptor.Aux[MutDescriptor] = {
    val newValidTs = currentTs
    if (currentTs > this.validTs) {
      if (
        ctx.validate(this) &&
        ((additionalHwd eq null) || ctx.validateHwd(additionalHwd))
      ) {
        assert((additionalHwd eq null) || (additionalHwd.version <= newValidTs))
        this._validTs = currentTs
        this
      } else {
        null
      }
    } else {
      // no need to validate:
      this
    }
  }

  private[mcas] final override def withNoNewVersion: MutDescriptor = {
    this._versionIncr = 0L
    this
  }

  private[choam] final override def hwdIterator: Iterator[LogEntry[Any]] = {
    this.map.valuesIterator
  }

  /** This is used by EMCAS instead of the above */
  private[mcas] final override def toWdArray(parent: EmcasDescriptor, instRo: Boolean): Array[WdLike[Any]] = {
    this.map.copyToArray(parent, flag = instRo, nullIfBlue = true)
  }

  final override def toString: String = {
    val m = this.map.toString(pre = "[", post = "]")
    val vi = if (versionIncr == MutDescriptor.DefaultVersionIncr) {
      ""
    } else {
      s", versionIncr = ${versionIncr}"
    }
    s"mcas.MutDescriptor(${m}, validTs = ${validTs}, readOnly = ${readOnly}${vi})"
  }

  final override def equals(that: Any): Boolean = {
    that match {
      case that: MutDescriptor =>
        (this eq that) || (
          (this.validTs == that.validTs) &&
          (this.versionIncr == that.versionIncr) &&
          (this.map == that.hamt)
        )
      case _ =>
        false
    }
  }

  final override def hashCode: Int = {
    var h = MurmurHash3.mix(0x9bae16ae, this.validTs.##)
    h = MurmurHash3.mix(h, this.versionIncr.##)
    h = MurmurHash3.mix(h, this.map.##)
    MurmurHash3.finalizeHash(h, this.map.size)
  }
}

object MutDescriptor {

  private final val DefaultVersionIncr =
    Version.Incr

  private[mcas] final def newEmptyFromVer(currentTs: Long): MutDescriptor = {
    new MutDescriptor(
      LogMapMut.newEmpty(),
      _validTs = currentTs,
      _versionIncr = DefaultVersionIncr,
    )
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy