Skip to content

Commit 87c5674

Browse files
committed
adding a lot of java doc
1 parent cb7e272 commit 87c5674

23 files changed

+964
-37
lines changed

fdb-extensions/src/main/java/com/apple/foundationdb/async/MoreAsyncUtil.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,23 @@ public static CompletableFuture<Void> swallowException(@Nonnull CompletableFutur
10571057
return result;
10581058
}
10591059

1060+
/**
1061+
* Method that provides the functionality of a for loop, however, in an asynchronous way. The result of this method
1062+
* is a {@link CompletableFuture} that represents the result of the last iteration of the loop body.
1063+
* @param startI an integer analogous to the starting value of a loop variable in a for loop
1064+
* @param startU an object of some type {@code U} that represents some initial state that is passed to the loop's
1065+
* initial state
1066+
* @param conditionPredicate a predicate on the loop variable that must be true before the next iteration is
1067+
* entered; analogous to the condition in a for loop
1068+
* @param stepFunction a unary operator used for modifying the loop variable after each iteration
1069+
* @param body a bi-function to be called for each iteration; this function is initially invoked using
1070+
* {@code startI} and {@code startU}; the result of the body is then passed into the next iterator's body
1071+
* together with a new value for the loop variable. In this way callers can access state inside an iteration
1072+
* that was computed in a previous iteration.
1073+
* @param executor the executor
1074+
* @param <U> the type of the result of the body {@link BiFunction}
1075+
* @return a {@link CompletableFuture} containing the result of the last iteration's body invocation.
1076+
*/
10601077
@Nonnull
10611078
public static <U> CompletableFuture<U> forLoop(final int startI, @Nullable final U startU,
10621079
@Nonnull final IntPredicate conditionPredicate,
@@ -1079,6 +1096,18 @@ public static <U> CompletableFuture<U> forLoop(final int startI, @Nullable final
10791096
}, executor).thenApply(ignored -> lastResultAtomic.get());
10801097
}
10811098

1099+
/**
1100+
* Method to iterate over some items, for each of which a body is executed asynchronously. The result of each such
1101+
* executed is then collected in a list and returned as a {@link CompletableFuture} over that list.
1102+
* @param items the items to iterate over
1103+
* @param body a function to be called for each item
1104+
* @param parallelism the maximum degree of parallelism this method should use
1105+
* @param executor the executor
1106+
* @param <T> the type of item
1107+
* @param <U> the type of the result
1108+
* @return a {@link CompletableFuture} containing a list of results collected from the individual body invocations
1109+
*/
1110+
@Nonnull
10821111
@SuppressWarnings("unchecked")
10831112
public static <T, U> CompletableFuture<List<U>> forEach(@Nonnull final Iterable<T> items,
10841113
@Nonnull final Function<T, CompletableFuture<U>> body,

fdb-extensions/src/main/java/com/apple/foundationdb/async/hnsw/BaseNeighborsChangeSet.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* InliningNode.java
2+
* BaseNeighborsChangeSet.java
33
*
44
* This source file is part of the FoundationDB open source project
55
*

fdb-extensions/src/main/java/com/apple/foundationdb/async/hnsw/CompactStorageAdapter.java

Lines changed: 133 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,29 +41,81 @@
4141
import java.util.List;
4242
import java.util.concurrent.CompletableFuture;
4343

44+
/**
45+
* The {@code CompactStorageAdapter} class is a concrete implementation of {@link StorageAdapter} for managing HNSW
46+
* graph data in a compact format.
47+
* <p>
48+
* It handles the serialization and deserialization of graph nodes to and from a persistent data store. This
49+
* implementation is optimized for space efficiency by storing nodes with their accompanying vector data and by storing
50+
* just neighbor primary keys. It extends {@link AbstractStorageAdapter} to inherit common storage logic.
51+
*/
4452
class CompactStorageAdapter extends AbstractStorageAdapter<NodeReference> implements StorageAdapter<NodeReference> {
4553
@Nonnull
4654
private static final Logger logger = LoggerFactory.getLogger(CompactStorageAdapter.class);
4755

56+
/**
57+
* Constructs a new {@code CompactStorageAdapter}.
58+
* <p>
59+
* This constructor initializes the adapter by delegating to the superclass,
60+
* setting up the necessary components for managing an HNSW graph.
61+
*
62+
* @param config the HNSW graph configuration, must not be null. See {@link HNSW.Config}.
63+
* @param nodeFactory the factory used to create new nodes of type {@link NodeReference}, must not be null.
64+
* @param subspace the {@link Subspace} where the graph data is stored, must not be null.
65+
* @param onWriteListener the listener to be notified of write events, must not be null.
66+
* @param onReadListener the listener to be notified of read events, must not be null.
67+
*/
4868
public CompactStorageAdapter(@Nonnull final HNSW.Config config, @Nonnull final NodeFactory<NodeReference> nodeFactory,
4969
@Nonnull final Subspace subspace,
5070
@Nonnull final OnWriteListener onWriteListener,
5171
@Nonnull final OnReadListener onReadListener) {
5272
super(config, nodeFactory, subspace, onWriteListener, onReadListener);
5373
}
5474

75+
/**
76+
* Returns this storage adapter instance, as it is already a compact storage adapter.
77+
* @return the current instance, which serves as its own compact representation.
78+
* This will never be {@code null}.
79+
*/
5580
@Nonnull
5681
@Override
5782
public StorageAdapter<NodeReference> asCompactStorageAdapter() {
5883
return this;
5984
}
6085

86+
/**
87+
* Returns this adapter as a {@code StorageAdapter} that supports inlining.
88+
* <p>
89+
* This operation is not supported by a compact storage adapter. Calling this method on this implementation will
90+
* always result in an {@code IllegalStateException}.
91+
*
92+
* @return an instance of {@code StorageAdapter} that supports inlining
93+
*
94+
* @throws IllegalStateException unconditionally, as this operation is not supported
95+
* on a compact storage adapter.
96+
*/
6197
@Nonnull
6298
@Override
6399
public StorageAdapter<NodeReferenceWithVector> asInliningStorageAdapter() {
64100
throw new IllegalStateException("cannot call this method on a compact storage adapter");
65101
}
66102

103+
/**
104+
* Asynchronously fetches a node from the database for a given layer and primary key.
105+
* <p>
106+
* This internal method constructs a raw byte key from the {@code layer} and {@code primaryKey}
107+
* within the store's data subspace. It then uses the provided {@link ReadTransaction} to
108+
* retrieve the raw value. If a value is found, it is deserialized into a {@link Node} object
109+
* using the {@code nodeFromRaw} method.
110+
*
111+
* @param readTransaction the transaction to use for the read operation
112+
* @param layer the layer of the node to fetch
113+
* @param primaryKey the primary key of the node to fetch
114+
*
115+
* @return a future that will complete with the fetched {@link Node}
116+
*
117+
* @throws IllegalStateException if the node cannot be found in the database for the given key
118+
*/
67119
@Nonnull
68120
@Override
69121
protected CompletableFuture<Node<NodeReference>> fetchNodeInternal(@Nonnull final ReadTransaction readTransaction,
@@ -80,20 +132,52 @@ protected CompletableFuture<Node<NodeReference>> fetchNodeInternal(@Nonnull fina
80132
});
81133
}
82134

135+
/**
136+
* Deserializes a raw key-value byte array pair into a {@code Node}.
137+
* <p>
138+
* This method first converts the {@code valueBytes} into a {@link Tuple} and then,
139+
* along with the {@code primaryKey}, constructs the final {@code Node} object.
140+
* It also notifies any registered {@link OnReadListener} about the raw key-value
141+
* read and the resulting node creation.
142+
*
143+
* @param layer the layer of the HNSW where this node resides
144+
* @param primaryKey the primary key for the node
145+
* @param keyBytes the raw byte representation of the node's key
146+
* @param valueBytes the raw byte representation of the node's value, which will be deserialized
147+
*
148+
* @return a non-null, deserialized {@link Node} object
149+
*/
83150
@Nonnull
84151
private Node<NodeReference> nodeFromRaw(final int layer, final @Nonnull Tuple primaryKey,
85152
@Nonnull final byte[] keyBytes, @Nonnull final byte[] valueBytes) {
86153
final Tuple nodeTuple = Tuple.fromBytes(valueBytes);
87-
final Node<NodeReference> node = nodeFromTuples(primaryKey, nodeTuple);
154+
final Node<NodeReference> node = nodeFromKeyValuesTuples(primaryKey, nodeTuple);
88155
final OnReadListener onReadListener = getOnReadListener();
89156
onReadListener.onNodeRead(layer, node);
90157
onReadListener.onKeyValueRead(layer, keyBytes, valueBytes);
91158
return node;
92159
}
93160

161+
/**
162+
* Constructs a compact {@link Node} from its representation as stored key and value tuples.
163+
* <p>
164+
* This method deserializes a node by extracting its components from the provided tuples. It verifies that the
165+
* node is of type {@link NodeKind#COMPACT} before delegating the final construction to
166+
* {@link #compactNodeFromTuples(Tuple, Tuple, Tuple)}. The {@code valueTuple} is expected to have a specific
167+
* structure: the serialized node kind at index 0, a nested tuple for the vector at index 1, and a nested
168+
* tuple for the neighbors at index 2.
169+
*
170+
* @param primaryKey the tuple representing the primary key of the node
171+
* @param valueTuple the tuple containing the serialized node data, including kind, vector, and neighbors
172+
*
173+
* @return the reconstructed compact {@link Node}
174+
*
175+
* @throws com.google.common.base.VerifyException if the node kind encoded in {@code valueTuple} is not
176+
* {@link NodeKind#COMPACT}
177+
*/
94178
@Nonnull
95-
private Node<NodeReference> nodeFromTuples(@Nonnull final Tuple primaryKey,
96-
@Nonnull final Tuple valueTuple) {
179+
private Node<NodeReference> nodeFromKeyValuesTuples(@Nonnull final Tuple primaryKey,
180+
@Nonnull final Tuple valueTuple) {
97181
final NodeKind nodeKind = NodeKind.fromSerializedNodeKind((byte)valueTuple.getLong(0));
98182
Verify.verify(nodeKind == NodeKind.COMPACT);
99183

@@ -105,6 +189,21 @@ private Node<NodeReference> nodeFromTuples(@Nonnull final Tuple primaryKey,
105189
return compactNodeFromTuples(primaryKey, vectorTuple, neighborsTuple);
106190
}
107191

192+
/**
193+
* Creates a compact in-memory representation of a graph node from its constituent storage tuples.
194+
* <p>
195+
* This method deserializes the raw data stored in {@code Tuple} objects into their
196+
* corresponding in-memory types. It extracts the vector, constructs a list of
197+
* {@link NodeReference} objects for the neighbors, and then uses a factory to
198+
* assemble the final {@code Node} object.
199+
* </p>
200+
*
201+
* @param primaryKey the tuple representing the node's primary key
202+
* @param vectorTuple the tuple containing the node's vector data
203+
* @param neighborsTuple the tuple containing a list of nested tuples, where each nested tuple represents a neighbor
204+
*
205+
* @return a new {@code Node} instance containing the deserialized data from the input tuples
206+
*/
108207
@Nonnull
109208
private Node<NodeReference> compactNodeFromTuples(@Nonnull final Tuple primaryKey,
110209
@Nonnull final Tuple vectorTuple,
@@ -120,6 +219,21 @@ private Node<NodeReference> compactNodeFromTuples(@Nonnull final Tuple primaryKe
120219
return getNodeFactory().create(primaryKey, vector, nodeReferences);
121220
}
122221

222+
/**
223+
* Writes the internal representation of a compact node to the data store within a given transaction.
224+
* This method handles the serialization of the node's vector and its final set of neighbors based on the
225+
* provided {@code neighborsChangeSet}.
226+
*
227+
* <p>The node is stored as a {@link Tuple} with the structure {@code (NodeKind, Vector, NeighborPrimaryKeys)}.
228+
* The key for the storage is derived from the node's layer and its primary key. After writing, it notifies any
229+
* registered write listeners via {@code onNodeWritten} and {@code onKeyValueWritten}.
230+
*
231+
* @param transaction the {@link Transaction} to use for the write operation.
232+
* @param node the {@link Node} to be serialized and written; it is processed as a {@link CompactNode}.
233+
* @param layer the graph layer index for the node, used to construct the storage key.
234+
* @param neighborsChangeSet a {@link NeighborsChangeSet} containing the additions and removals, which are
235+
* merged to determine the final set of neighbors to be written.
236+
*/
123237
@Override
124238
public void writeNodeInternal(@Nonnull final Transaction transaction, @Nonnull final Node<NodeReference> node,
125239
final int layer, @Nonnull final NeighborsChangeSet<NodeReference> neighborsChangeSet) {
@@ -151,6 +265,22 @@ public void writeNodeInternal(@Nonnull final Transaction transaction, @Nonnull f
151265
}
152266
}
153267

268+
/**
269+
* Scans a given layer for nodes, returning an iterable over the results.
270+
* <p>
271+
* This method reads a limited number of nodes from a specific layer in the underlying data store.
272+
* The scan can be started from a specific point using the {@code lastPrimaryKey} parameter, which is
273+
* useful for paginating through the nodes in a large layer.
274+
*
275+
* @param readTransaction the transaction to use for reading data; must not be {@code null}
276+
* @param layer the layer to scan for nodes
277+
* @param lastPrimaryKey the primary key of the last node from a previous scan. If {@code null},
278+
* the scan starts from the beginning of the layer.
279+
* @param maxNumRead the maximum number of nodes to read in this scan
280+
*
281+
* @return an {@link Iterable} of {@link Node} objects found in the specified layer,
282+
* limited by {@code maxNumRead}
283+
*/
154284
@Nonnull
155285
@Override
156286
public Iterable<Node<NodeReference>> scanLayer(@Nonnull final ReadTransaction readTransaction, int layer,

fdb-extensions/src/main/java/com/apple/foundationdb/async/hnsw/DeleteNeighborsChangeSet.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* InliningNode.java
2+
* DeleteNeighborsChangeSet.java
33
*
44
* This source file is part of the FoundationDB open source project
55
*

fdb-extensions/src/main/java/com/apple/foundationdb/async/hnsw/EntryNodeReference.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* NodeWithLayer.java
2+
* EntryNodeReference.java
33
*
44
* This source file is part of the FoundationDB open source project
55
*
@@ -26,18 +26,50 @@
2626
import javax.annotation.Nonnull;
2727
import java.util.Objects;
2828

29+
/**
30+
* Represents an entry reference to a node within a hierarchical graph structure.
31+
* <p>
32+
* This class extends {@link NodeReferenceWithVector} by adding a {@code layer}
33+
* attribute. It is used to encapsulate all the necessary information for an
34+
* entry point into a specific layer of the graph, including its unique identifier
35+
* (primary key), its vector representation, and its hierarchical level.
36+
*/
2937
class EntryNodeReference extends NodeReferenceWithVector {
3038
private final int layer;
3139

40+
/**
41+
* Constructs a new reference to an entry node.
42+
* <p>
43+
* This constructor initializes the node with its primary key, its associated vector,
44+
* and the specific layer it belongs to within a hierarchical graph structure. It calls the
45+
* superclass constructor to set the {@code primaryKey} and {@code vector}.
46+
*
47+
* @param primaryKey the primary key identifying the node. Must not be {@code null}.
48+
* @param vector the vector data associated with the node. Must not be {@code null}.
49+
* @param layer the layer number where this entry node is located.
50+
*/
3251
public EntryNodeReference(@Nonnull final Tuple primaryKey, @Nonnull final Vector<Half> vector, final int layer) {
3352
super(primaryKey, vector);
3453
this.layer = layer;
3554
}
3655

56+
/**
57+
* Gets the layer value for this object.
58+
* @return the integer representing the layer
59+
*/
3760
public int getLayer() {
3861
return layer;
3962
}
4063

64+
/**
65+
* Compares this {@code EntryNodeReference} to the specified object for equality.
66+
* <p>
67+
* The result is {@code true} if and only if the argument is an instance of {@code EntryNodeReference}, the
68+
* superclass's {@link #equals(Object)} method returns {@code true}, and the {@code layer} fields of both objects
69+
* are equal.
70+
* @param o the object to compare this {@code EntryNodeReference} against.
71+
* @return {@code true} if the given object is equal to this one; {@code false} otherwise.
72+
*/
4173
@Override
4274
public boolean equals(final Object o) {
4375
if (!(o instanceof EntryNodeReference)) {
@@ -49,6 +81,13 @@ public boolean equals(final Object o) {
4981
return layer == ((EntryNodeReference)o).layer;
5082
}
5183

84+
/**
85+
* Generates a hash code for this object.
86+
* <p>
87+
* The hash code is computed by combining the hash code of the superclass with the hash code of the {@code layer}
88+
* field. This implementation is consistent with the contract of {@link Object#hashCode()}.
89+
* @return a hash code value for this object.
90+
*/
5291
@Override
5392
public int hashCode() {
5493
return Objects.hash(super.hashCode(), layer);

fdb-extensions/src/main/java/com/apple/foundationdb/async/hnsw/HNSWHelpers.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
public class HNSWHelpers {
3232
private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
3333

34+
/**
35+
* This is a utility class and is not intended to be instantiated.
36+
*/
3437
private HNSWHelpers() {
3538
// nothing
3639
}
@@ -51,11 +54,23 @@ public static String bytesToHex(byte[] bytes) {
5154
return "0x" + new String(hexChars).replaceFirst("^0+(?!$)", "");
5255
}
5356

57+
/**
58+
* Returns a {@code Half} instance representing the specified {@code double} value, rounded to the nearest
59+
* representable half-precision float value.
60+
* @param d the {@code double} value to be converted.
61+
* @return a non-null {@link Half} instance representing {@code d}.
62+
*/
5463
@Nonnull
5564
public static Half halfValueOf(final double d) {
5665
return Half.shortBitsToHalf(Half.halfToShortBits(Half.valueOf(d)));
5766
}
5867

68+
/**
69+
* Returns a {@code Half} instance representing the specified {@code float} value, rounded to the nearest
70+
* representable half-precision float value.
71+
* @param f the {@code float} value to be converted.
72+
* @return a non-null {@link Half} instance representing {@code f}.
73+
*/
5974
@Nonnull
6075
public static Half halfValueOf(final float f) {
6176
return Half.shortBitsToHalf(Half.halfToShortBits(Half.valueOf(f)));

fdb-extensions/src/main/java/com/apple/foundationdb/async/hnsw/InliningStorageAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* CompactStorageAdapter.java
2+
* InliningStorageAdapter.java
33
*
44
* This source file is part of the FoundationDB open source project
55
*

0 commit comments

Comments
 (0)