Top Description Inners Fields Constructors Methods
org.graalvm.collections

public Class SeqLockPrefixTree

extends Object
Class Inheritance
Imports
java.util.ArrayList, .List, java.util.concurrent.atomic.AtomicLong, java.util.function.BiConsumer, .BiFunction

Thread-safe prefix-tree implementation in which keys are sequences of 64-bit values, and the values are 64-bit values.

The prefix tree supports a single operation root, which returns the root node. The nodes support the following operations: at to obtain a child node, value to obtain the value at the current node, setValue to atomically set the value and incValue to atomically increment the value.

The prefix tree is implemented as follows. The tree points to the root node. Each node points to a set of child nodes, where each child is associated with a key. Each node additionally holds an arity, which is the number of children, and the 64-bit value of that node.

The set of child nodes can be represented as null if the set is empty, an array-list if the the set is small, or a hash table if the set is large. In all cases, the keys and the child nodes are kept in separate arrays.

The at operation, which takes a node and a key, and returns the corresponding child node, deserves an additional explanation. This operation creates an existing child associated with the key, or atomically creates a new child, if there was no child for that key.

The at operation is implemented as follows. There is a fast-path, which executes when the child node already exists, and there are no concurrent modifications at that node, and the slow-path, which executes when the child does not exist or when there is a concurrent modification. To ensure that the slow path does not obtain a monitor, the fast-path relies on a seqlock. This is a lightweight read-write lock that consists of a single 64-bit counter, whose value is even when the lock is in the read mode, and odd when the lock is in the write mode. The lock can be held by any number of readers, but at most 1 writer at any time.

In the read-mode, the reader must verify that the value of the lock is even and that it did not change from the point when the read started until the point when the read ended, and additionally takes care that reading an invalid state does not crash the execution. If the read fails for either of these reasons, the reader proceeds to the write-mode. In the write-mode, the reader or the writer enters a heavy lock (i.e. monitor) and then increments the seqlock's value by one, does the modification, and then increments the seqlock's value by one to make it even again. The volatile access semantics of the seqlock's value, along with the fact that the node's data only "grows" over time, are the properties that ensure the correctness of this implementation.

Since
22.3

Nested and Inner Type Summary

Modifier and TypeClass and Description
public static class
pack-priv static interface

Field Summary

Modifier and TypeField and Description
private static final long
private static final double
private static final int
private static final int
private static final int
private final SeqLockPrefixTree.Node

Constructor Summary

AccessConstructor and Description
public
SeqLockPrefixTree()

Create new SeqLockPrefixTree with root being a Node with key 0.

Method Summary

Modifier and TypeMethod and Description
public SeqLockPrefixTree.Node

Returns:

the root of the tree
root
()

The root node of the tree.

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

EMPTY_KEYback to summary
private static final long EMPTY_KEY
HASH_NODE_LOAD_FACTORback to summary
private static final double HASH_NODE_LOAD_FACTOR
INITIAL_HASH_NODE_SIZEback to summary
private static final int INITIAL_HASH_NODE_SIZE
INITIAL_LINEAR_NODE_SIZEback to summary
private static final int INITIAL_LINEAR_NODE_SIZE
MAX_LINEAR_NODE_SIZEback to summary
private static final int MAX_LINEAR_NODE_SIZE
rootback to summary
private final SeqLockPrefixTree.Node root

Constructor Detail

SeqLockPrefixTreeback to summary
public SeqLockPrefixTree()

Create new SeqLockPrefixTree with root being a Node with key 0.

Since
22.3

Method Detail

rootback to summary
public SeqLockPrefixTree.Node root()

The root node of the tree.

Returns:SeqLockPrefixTree.Node

the root of the tree

Since
22.3
org.graalvm.collections back to summary

public final Class SeqLockPrefixTree.Node

extends AtomicLong
Class Inheritance

Since
22.3

Field Summary

Modifier and TypeField and Description
private volatile int
private volatile SeqLockPrefixTree.Node[]
private volatile long[]
private volatile long
private static final long

Constructor Summary

AccessConstructor and Description
private
Node()

Method Summary

Modifier and TypeMethod and Description
private void
private void
private void
public SeqLockPrefixTree.Node

Returns:

The child with the given childKey.
at
(long
the key of the child.
key
)

Get existing (or create if missing) child with the given key.

private synchronized <R> R
private void
private static SeqLockPrefixTree.Node
findChild(long[] keysSnapshot, SeqLockPrefixTree.Node[] childrenSnapshot, long key)

private SeqLockPrefixTree.Node
private void
private static int
hash(long key)

public long

Returns:

newly incremented value of the LockFreePrefixTree.Node.
incValue
()

Increment value.

private boolean
public long

Returns:

the value of the seqlock.
seqlockValue
()

public void
setValue(long
the new value.
value
)

Set the value for the LockFreePrefixTree.Node.

public synchronized <
The type of the context
C
>
void
topDown(C
The context for the root of the tree
currentContext
,
BiFunction<C, Long, C>
A function defining how the context for children is created
createContext
,
BiConsumer<C, Long>
A function that consumes the nodes value
consumeValue
)

Traverse the tree top-down while maintaining a context.

public String
toString()

Overrides java.util.concurrent.atomic.AtomicLong.toString.

Returns the String representation of the current value.

private synchronized SeqLockPrefixTree.Node
tryAddChild(long key)

public long

Returns:

The value of the LockFreePrefixTree.Node
value
()

Inherited from java.util.concurrent.atomic.AtomicLong:
accumulateAndGetaddAndGetcompareAndExchangecompareAndExchangeAcquirecompareAndExchangeReleasecompareAndSetdecrementAndGetdoubleValuefloatValuegetgetAcquiregetAndAccumulategetAndAddgetAndDecrementgetAndIncrementgetAndSetgetAndUpdategetOpaquegetPlainincrementAndGetintValuelazySetlongValuesetsetOpaquesetPlainsetReleaseupdateAndGetweakCompareAndSetweakCompareAndSetAcquireweakCompareAndSetPlainweakCompareAndSetReleaseweakCompareAndSetVolatile

Field Detail

arityback to summary
private volatile int arity
childrenback to summary
private volatile SeqLockPrefixTree.Node[] children
keysback to summary
private volatile long[] keys
seqlockback to summary
private volatile long seqlock
serialVersionUIDback to summary
private static final long serialVersionUID

Hides java.util.concurrent.atomic.AtomicLong.serialVersionUID.

Constructor Detail

Nodeback to summary
private Node()

Method Detail

addChildToHashNodeback to summary
private void addChildToHashNode(long key, SeqLockPrefixTree.Node child)
addChildToLinearNodeback to summary
private void addChildToLinearNode(long key, SeqLockPrefixTree.Node child)
Annotations
@SuppressFBWarnings:VO_VOLATILE_INCREMENT
justification:called from synchronized tryAddChild
addChildToNonFullHashNodeback to summary
private void addChildToNonFullHashNode(long key, SeqLockPrefixTree.Node child)
Annotations
@SuppressFBWarnings:VO_VOLATILE_INCREMENT
justification:called indirectly from synchronized tryAddChild
atback to summary
public SeqLockPrefixTree.Node at(long key)

Get existing (or create if missing) child with the given key.

Parameters
key:long

the key of the child.

Returns:SeqLockPrefixTree.Node

The child with the given childKey.

Since
22.3
bottomUpback to summary
private synchronized <R> R bottomUp(SeqLockPrefixTree.Visitor<R> visitor)
Annotations
@SuppressWarnings:unused
convertToHashNodeback to summary
private void convertToHashNode()
findChildback to summary
private static SeqLockPrefixTree.Node findChild(long[] keysSnapshot, SeqLockPrefixTree.Node[] childrenSnapshot, long key)
findChildLockFreeback to summary
private SeqLockPrefixTree.Node findChildLockFree(long key)
growHashback to summary
private void growHash()
hashback to summary
private static int hash(long key)
incValueback to summary
public long incValue()

Increment value.

Returns:long

newly incremented value of the LockFreePrefixTree.Node.

Since
22.3
mustGrowHashback to summary
private boolean mustGrowHash()
seqlockValueback to summary
public long seqlockValue()
Returns:long

the value of the seqlock.

Since
22.3
setValueback to summary
public void setValue(long value)

Set the value for the LockFreePrefixTree.Node.

Parameters
value:long

the new value.

Since
22.3
topDownback to summary
public synchronized <C> void topDown(C currentContext, BiFunction<C, Long, C> createContext, BiConsumer<C, Long> consumeValue)

Traverse the tree top-down while maintaining a context. The context is a generic data structure corresponding to the depth of the traversal, i.e. given the currentContext and a createContext function, a new context is created for each visited child using the createContext function, starting with initialContext.

Parameters
<C>
The type of the context
currentContext:C

The context for the root of the tree

createContext:BiFunction<C, Long, C>

A function defining how the context for children is created

consumeValue:BiConsumer<C, Long>

A function that consumes the nodes value

Annotations
@SuppressWarnings:unused
Since
22.3
toStringback to summary
public String toString()

Overrides java.util.concurrent.atomic.AtomicLong.toString.

Doc from java.util.concurrent.atomic.AtomicLong.toString.

Returns the String representation of the current value.

Returns:String

the String representation of the current value

Annotations
@Override
Since
22.3
tryAddChildback to summary
private synchronized SeqLockPrefixTree.Node tryAddChild(long key)
Annotations
@SuppressFBWarnings:VO_VOLATILE_INCREMENT
justification:in synchronized method
valueback to summary
public long value()
Returns:long

The value of the LockFreePrefixTree.Node

Since
22.3
org.graalvm.collections back to summary

pack-priv Interface SeqLockPrefixTree.Visitor<R>


Method Summary

Modifier and TypeMethod and Description
public R
visit(SeqLockPrefixTree.Node n, List<R> childResults)

Method Detail

visitback to summary
public R visit(SeqLockPrefixTree.Node n, List<R> childResults)